diff options
| -rw-r--r-- | bgpd/bgp_fsm.c | 3 | ||||
| -rw-r--r-- | bgpd/bgp_packet.c | 21 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 64 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 5 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 4 | ||||
| -rwxr-xr-x | configure.ac | 4 | ||||
| -rw-r--r-- | debian/control | 2 | ||||
| -rw-r--r-- | doc/developer/building-libyang.rst | 15 | ||||
| -rw-r--r-- | doc/developer/lists.rst | 61 | ||||
| -rw-r--r-- | doc/user/bgp.rst | 12 | ||||
| -rw-r--r-- | redhat/frr.spec.in | 2 | ||||
| -rw-r--r-- | yang/frr-interface.yang | 6 | ||||
| -rw-r--r-- | yang/frr-ripd.yang | 6 | ||||
| -rw-r--r-- | yang/frr-ripngd.yang | 2 | ||||
| -rw-r--r-- | yang/frr-route-map.yang | 2 | ||||
| -rw-r--r-- | yang/frr-zebra.yang | 20 |
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."; } |
