summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_fsm.c3
-rw-r--r--bgpd/bgp_packet.c21
-rw-r--r--bgpd/bgp_vty.c64
-rw-r--r--bgpd/bgpd.c5
-rw-r--r--bgpd/bgpd.h4
-rwxr-xr-xconfigure.ac4
-rw-r--r--debian/control2
-rw-r--r--doc/developer/building-libyang.rst15
-rw-r--r--doc/developer/lists.rst61
-rw-r--r--doc/user/bgp.rst12
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--yang/frr-interface.yang6
-rw-r--r--yang/frr-ripd.yang6
-rw-r--r--yang/frr-ripngd.yang2
-rw-r--r--yang/frr-route-map.yang2
-rw-r--r--yang/frr-zebra.yang20
16 files changed, 189 insertions, 40 deletions
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 4575b8afbe..14dcf2b593 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1105,6 +1105,9 @@ void bgp_fsm_change_status(struct peer *peer, int status)
peer->ostatus = peer->status;
peer->status = status;
+ /* Reset received keepalives counter on every FSM change */
+ peer->rtt_keepalive_rcv = 0;
+
/* Fire backward transition hook if that's the case */
if (peer->ostatus > peer->status)
hook_call(peer_backward_transition, peer);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 0d81403803..15dba37667 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1432,6 +1432,27 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
bgp_update_implicit_eors(peer);
+ peer->rtt = sockopt_tcp_rtt(peer->fd);
+
+ /* If the peer's RTT is higher than expected, shutdown
+ * the peer automatically.
+ */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN)
+ && peer->rtt > peer->rtt_expected) {
+
+ peer->rtt_keepalive_rcv++;
+
+ if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) {
+ zlog_warn(
+ "%s shutdown due to high round-trip-time (%dms > %dms)",
+ peer->host, peer->rtt, peer->rtt_expected);
+ peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
+ }
+ } else {
+ if (peer->rtt_keepalive_rcv)
+ peer->rtt_keepalive_rcv--;
+ }
+
return Receive_KEEPALIVE_message;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 2af791333e..47c5237aa6 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4573,6 +4573,64 @@ ALIAS(no_neighbor_shutdown_msg, no_neighbor_shutdown_cmd,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Administratively shut down this neighbor\n")
+DEFUN(neighbor_shutdown_rtt,
+ neighbor_shutdown_rtt_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt (1-65535) [count (1-255)]",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Administratively shut down this neighbor\n"
+ "Shutdown if round-trip-time is higher than expected\n"
+ "Round-trip-time in milliseconds\n"
+ "Specify the number of keepalives before shutdown\n"
+ "The number of keepalives with higher RTT to shutdown\n")
+{
+ int idx_peer = 1;
+ int idx_rtt = 4;
+ int idx_count = 0;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ peer->rtt_expected = strtol(argv[idx_rtt]->arg, NULL, 10);
+
+ if (argv_find(argv, argc, "count", &idx_count))
+ peer->rtt_keepalive_conf =
+ strtol(argv[idx_count + 1]->arg, NULL, 10);
+
+ return peer_flag_set_vty(vty, argv[idx_peer]->arg,
+ PEER_FLAG_RTT_SHUTDOWN);
+}
+
+DEFUN(no_neighbor_shutdown_rtt,
+ no_neighbor_shutdown_rtt_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt [(1-65535) [count (1-255)]]",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Administratively shut down this neighbor\n"
+ "Shutdown if round-trip-time is higher than expected\n"
+ "Round-trip-time in milliseconds\n"
+ "Specify the number of keepalives before shutdown\n"
+ "The number of keepalives with higher RTT to shutdown\n")
+{
+ int idx_peer = 2;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ peer->rtt_expected = 0;
+ peer->rtt_keepalive_conf = 1;
+
+ return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
+ PEER_FLAG_RTT_SHUTDOWN);
+}
+
/* neighbor capability dynamic. */
DEFUN (neighbor_capability_dynamic,
neighbor_capability_dynamic_cmd,
@@ -14922,6 +14980,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s shutdown\n", addr);
}
+ if (peergroup_flag_check(peer, PEER_FLAG_RTT_SHUTDOWN))
+ vty_out(vty, " neighbor %s shutdown rtt %u count %u\n", addr,
+ peer->rtt_expected, peer->rtt_keepalive_conf);
+
/* bfd */
if (peer->bfd_info) {
if (!peer_group_active(peer) || !g_peer->bfd_info) {
@@ -16731,6 +16793,8 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &no_neighbor_shutdown_cmd);
install_element(BGP_NODE, &neighbor_shutdown_msg_cmd);
install_element(BGP_NODE, &no_neighbor_shutdown_msg_cmd);
+ install_element(BGP_NODE, &neighbor_shutdown_rtt_cmd);
+ install_element(BGP_NODE, &no_neighbor_shutdown_rtt_cmd);
/* "neighbor capability extended-nexthop" commands.*/
install_element(BGP_NODE, &neighbor_capability_enhe_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index ab2a2c3323..b654e85206 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1604,6 +1604,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
/* Default TTL set. */
peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : BGP_DEFAULT_TTL;
+ /* Default configured keepalives count for shutdown rtt command */
+ peer->rtt_keepalive_conf = 1;
+
SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
if (afi && safi) {
@@ -3866,6 +3869,7 @@ struct peer_flag_action {
static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_PASSIVE, 0, peer_change_reset},
{PEER_FLAG_SHUTDOWN, 0, peer_change_reset},
+ {PEER_FLAG_RTT_SHUTDOWN, 0, peer_change_none},
{PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none},
@@ -3968,6 +3972,7 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag)
peer_nsf_stop(peer);
UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+
if (peer->t_pmax_restart) {
BGP_TIMER_OFF(peer->t_pmax_restart);
if (bgp_debug_neighbor_events(peer))
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index cf0da8c542..2aa0690025 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -972,6 +972,9 @@ struct peer {
int fd; /* File descriptor */
int ttl; /* TTL of TCP connection to the peer. */
int rtt; /* Estimated round-trip-time from TCP_INFO */
+ int rtt_expected; /* Expected round-trip-time for a peer */
+ uint8_t rtt_keepalive_rcv; /* Received count for RTT shutdown */
+ uint8_t rtt_keepalive_conf; /* Configured count for RTT shutdown */
int gtsm_hops; /* minimum hopcount to peer */
char *desc; /* Description of the peer. */
unsigned short port; /* Destination port for peer */
@@ -1122,6 +1125,7 @@ struct peer {
#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1U << 23) /* Helper */
#define PEER_FLAG_GRACEFUL_RESTART (1U << 24) /* Graceful Restart */
#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */
+#define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
diff --git a/configure.ac b/configure.ac
index ae116ef754..715efbcdae 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1728,8 +1728,8 @@ AC_SUBST([SNMP_CFLAGS])
dnl ---------------
dnl libyang
dnl ---------------
-PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.105], , [
- AC_MSG_ERROR([libyang (>= 0.16.105) was not found on your system.])
+PKG_CHECK_MODULES([LIBYANG], [libyang >= 1.0.184], , [
+ AC_MSG_ERROR([libyang (>= 1.0.184) was not found on your system.])
])
ac_cflags_save="$CFLAGS"
CFLAGS="$CFLAGS $LIBYANG_CFLAGS"
diff --git a/debian/control b/debian/control
index f4275471d5..fca6956760 100644
--- a/debian/control
+++ b/debian/control
@@ -24,7 +24,7 @@ Build-Depends:
libsnmp-dev,
libssh-dev <!pkg.frr.nortrlib>,
libsystemd-dev <!pkg.frr.nosystemd>,
- libyang-dev (>= 0.16.74),
+ libyang-dev (>= 1.0.184),
pkg-config,
python3,
python3-dev,
diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst
index f50b8cf72d..56f6f4f14e 100644
--- a/doc/developer/building-libyang.rst
+++ b/doc/developer/building-libyang.rst
@@ -5,12 +5,16 @@ library.
**Option 1: Binary Install**
-The FRR project builds binary ``libyang`` packages, which we offer for download
-`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
+The FRR project builds some binary ``libyang`` packages.
+
+RPM packages are at our `RPM repository <rpm.frrouting.org>`_
+
+DEB packages are available as CI artifacts `here
+<https://ci1.netdef.org/browse/LIBYANG-LY1REL-DEB10AMD64-4/artifact>`_.
.. warning::
- ``libyang`` version 0.16.105 or newer is required to build FRR.
+ ``libyang`` version 1.0.184 or newer is required to build FRR.
.. note::
@@ -50,8 +54,3 @@ The FRR project builds binary ``libyang`` packages, which we offer for download
-D CMAKE_BUILD_TYPE:String="Release" ..
make
sudo make install
-
-When building ``libyang`` version ``0.16.x`` it's also necessary to pass the
-``-DENABLE_CACHE=OFF`` parameter to ``cmake`` to work around a
-`known bug <https://github.com/CESNET/libyang/issues/752>`_ in libyang.
-
diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst
index 9355141aa4..28b21533c0 100644
--- a/doc/developer/lists.rst
+++ b/doc/developer/lists.rst
@@ -497,6 +497,7 @@ API for hash tables
Items that compare as equal cannot be inserted. Refer to the notes
about sorted structures in the previous section.
+
.. c:function:: void Z_init_size(struct Z_head *, size_t size)
Same as :c:func:`Z_init()` but preset the minimum hash table to
@@ -506,6 +507,66 @@ Hash tables also support :c:func:`Z_add()` and :c:func:`Z_find()` with
the same semantics as noted above. :c:func:`Z_find_gteq()` and
:c:func:`Z_find_lt()` are **not** provided for hash tables.
+Hash table invariants
+^^^^^^^^^^^^^^^^^^^^^
+
+There are several ways to injure yourself using the hash table API.
+
+First, note that there are two functions related to computing uniqueness of
+objects inserted into the hash table. There is a hash function and a comparison
+function. The hash function computes the hash of the object. Our hash table
+implementation uses `chaining
+<https://en.wikipedia.org/wiki/Hash_table#Separate_chaining_with_linked_lists>`_.
+This means that your hash function does not have to be perfect; multiple
+objects having the same computed hash will be placed into a linked list
+corresponding to that key. The closer to perfect the hash function, the better
+performance, as items will be more evenly distributed and the chain length will
+not be long on any given lookup, minimizing the number of list operations
+required to find the correct item. However, the comparison function *must* be
+perfect, in the sense that any two unique items inserted into the hash table
+must compare not equal. At insertion time, if you try to insert an item that
+compares equal to an existing item the insertion will not happen and
+``hash_get()`` will return the existing item. However, this invariant *must* be
+maintained while the object is in the hash table. Suppose you insert items
+``A`` and ``B`` into the hash table which both hash to the same value ``1234``
+but do not compare equal. They will be placed in a chain like so::
+
+ 1234 : A -> B
+
+Now suppose you do something like this elsewhere in the code::
+
+ *A = *B
+
+I.e. you copy all fields of ``B`` into ``A``, such that the comparison function
+now says that they are equal based on their contents. At this point when you
+look up ``B`` in the hash table, ``hash_get()`` will search the chain for the
+first item that compares equal to ``B``, which will be ``A``. This leads to
+insidious bugs.
+
+.. warning::
+
+ Never modify the values looked at by the comparison or hash functions after
+ inserting an item into a hash table.
+
+A similar situation can occur with the hash allocation function. ``hash_get()``
+accepts a function pointer that it will call to get the item that should be
+inserted into the list if the provided item is not already present. There is a
+builtin function, ``hash_alloc_intern``, that will simply return the item you
+provided; if you always want to store the value you pass to ``hash_get`` you
+should use this one. If you choose to provide a different one, that function
+*must* return a new item that hashes and compares equal to the one you provided
+to ``hash_get()``. If it does not the behavior of the hash table is undefined.
+
+.. warning::
+
+ Always make sure your hash allocation function returns a value that hashes
+ and compares equal to the item you provided to ``hash_get()``.
+
+Finally, if you maintain pointers to items you have inserted into a hash table,
+then before deallocating them you must release them from the hash table. This
+is basic memory management but worth repeating as bugs have arisen from failure
+to do this.
+
API for heaps
-------------
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 6b6773e7e4..63f3d05a93 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1256,14 +1256,14 @@ Defining Peers
The time in milliseconds that BGP will delay before deciding what peers
can be put into an update-group together in order to generate a single
update for them. The default time is 1000.
-
+
.. _bgp-configuring-peers:
Configuring Peers
^^^^^^^^^^^^^^^^^
-.. index:: [no] neighbor PEER shutdown [message MSG...]
-.. clicmd:: [no] neighbor PEER shutdown [message MSG...]
+.. index:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
+.. clicmd:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
Shutdown the peer. We can delete the neighbor's configuration by
``no neighbor PEER remote-as ASN`` but all configuration of the neighbor
@@ -1272,6 +1272,12 @@ Configuring Peers
Optionally you can specify a shutdown message `MSG`.
+ Also, you can specify optionally _rtt_ in milliseconds to automatically
+ shutdown the peer if round-trip-time becomes higher than defined.
+
+ Additional _count_ parameter is the number of keepalive messages to count
+ before shutdown the peer if round-trip-time becomes higher than defined.
+
.. index:: [no] neighbor PEER disable-connected-check
.. clicmd:: [no] neighbor PEER disable-connected-check
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 929214a142..bd0d5b27f4 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -170,7 +170,7 @@ BuildRequires: make
BuildRequires: ncurses-devel
BuildRequires: readline-devel
BuildRequires: texinfo
-BuildRequires: libyang-devel >= 0.16.74
+BuildRequires: libyang-devel >= 1.0.184
%if 0%{?rhel} && 0%{?rhel} < 7
#python27-devel is available from ius community repo for RedHat/CentOS 6
BuildRequires: python27-devel
diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang
index dade9f97fe..46c03a1d1f 100644
--- a/yang/frr-interface.yang
+++ b/yang/frr-interface.yang
@@ -300,11 +300,7 @@ module frr-interface {
}
leaf vrf {
- type string {
- length "1..16";
- }
- /* yang version 0.16 having issue accessing leafref. */
- /* type frr-vrf:vrf-ref;*/
+ type frr-vrf:vrf-ref;
description
"VRF this interface is associated with.";
}
diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang
index 4e5795b8f7..f5775ab968 100644
--- a/yang/frr-ripd.yang
+++ b/yang/frr-ripd.yang
@@ -143,7 +143,7 @@ module frr-ripd {
"Enable RIP on the specified IP network.";
}
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
description
"Enable RIP on the specified interface.";
}
@@ -204,14 +204,14 @@ module frr-ripd {
}
leaf-list passive-interface {
when "../passive-default = 'false'";
- type string;
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is disabled.";
}
leaf-list non-passive-interface {
when "../passive-default = 'true'";
- type string;
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is enabled.";
diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang
index 47ae67b238..52e208b2c9 100644
--- a/yang/frr-ripngd.yang
+++ b/yang/frr-ripngd.yang
@@ -101,7 +101,7 @@ module frr-ripngd {
"Enable RIPng on the specified IPv6 network.";
}
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
description
"Enable RIPng on the specified interface.";
}
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index b895cd12a4..c9d35938cb 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -249,7 +249,7 @@ module frr-route-map {
case interface {
when "./condition = 'interface'";
leaf interface {
- type string;
+ type frr-interface:interface-ref;
}
}
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 7762c75d68..2efc45c146 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -393,9 +393,7 @@ module frr-zebra {
}
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The tenant VRF.";
}
@@ -715,9 +713,7 @@ module frr-zebra {
choice vrf-choice {
case single {
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"Retrieve routes in a non-default vrf.";
}
@@ -815,9 +811,7 @@ module frr-zebra {
choice vrf-choice {
case single {
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"Retrieve routes in a non-default vrf.";
}
@@ -853,9 +847,7 @@ module frr-zebra {
output {
list vrf-list {
leaf name {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The VRF name";
}
@@ -910,9 +902,7 @@ module frr-zebra {
output {
list vrf-vni-list {
leaf vrf-name {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The VRF name.";
}