bgpd-ebgp-multihop-fix.patch

BGP: Fix EBGP multihop transitions correctly

Since BGP connection setup has migrated to using NHT to decide when to bring a
session up, we have to handle ebgp multihop transitions correctly to ensure NHT
registrations are correctly handled.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2015-05-19 18:45:53 -07:00
parent 4125bb6716
commit e5cc509c34
5 changed files with 136 additions and 56 deletions

View File

@ -148,7 +148,7 @@ bgp_update_sock_send_buffer_size (int fd)
}
}
static void
int
bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
{
char buf[INET_ADDRSTRLEN];
@ -164,6 +164,7 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
__func__,
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
errno);
return ret;
}
}
else if (peer->gtsm_hops)
@ -178,6 +179,7 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
__func__,
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
errno);
return ret;
}
ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock,
MAXTTL + 1 - peer->gtsm_hops);
@ -187,8 +189,11 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
__func__,
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
errno);
return ret;
}
}
return ret;
}
/* Accept bgp connection. */
@ -305,7 +310,10 @@ bgp_accept (struct thread *thread)
peer_delete(peer1->doppelganger);
}
bgp_set_socket_ttl (peer1, bgp_sock);
if (bgp_set_socket_ttl (peer1, bgp_sock) < 0)
if (bgp_debug_neighbor_events(peer1))
zlog_debug ("[Event] Unable to set min/max TTL on peer %s, Continuing",
peer1->host);
peer = peer_create (&su, peer1->conf_if, peer1->bgp, peer1->local_as,
peer1->as, peer1->as_type, 0, 0);
@ -453,7 +461,8 @@ bgp_connect (struct peer *peer)
/* Set socket send buffer size */
bgp_update_sock_send_buffer_size(peer->fd);
bgp_set_socket_ttl (peer, peer->fd);
if (bgp_set_socket_ttl (peer, peer->fd) < 0)
return -1;
sockopt_reuseaddr (peer->fd);
sockopt_reuseport (peer->fd);

View File

@ -29,5 +29,6 @@ extern int bgp_connect (struct peer *);
extern int bgp_getsockname (struct peer *);
extern int bgp_md5_set (struct peer *);
extern int bgp_set_socket_ttl(struct peer *, int fd);
#endif /* _QUAGGA_BGP_NETWORK_H */

View File

@ -3568,7 +3568,13 @@ 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);
{
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
}
}
else
{
@ -3580,8 +3586,11 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
peer->ttl = group->conf->ttl;
if (peer->fd >= 0)
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
}
}
return 0;
@ -3606,8 +3615,11 @@ peer_ebgp_multihop_unset (struct peer *peer)
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);
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
}
else
{
@ -3618,9 +3630,15 @@ peer_ebgp_multihop_unset (struct peer *peer)
continue;
peer->ttl = 1;
if (peer->fd >= 0)
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
{
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
}
}
}
return 0;
@ -5505,53 +5523,79 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
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 ((peer->gtsm_hops == 0) && (peer->sort != BGP_PEER_IBGP))
{
if (is_ebgp_multihop_configured (peer))
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;
}
peer->gtsm_hops = gtsm_hops;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
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);
if (peer->status != Established && peer->doppelganger)
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
MAXTTL + 1 - gtsm_hops);
/* Calling ebgp multihop also resets the session.
* On restart, NHT will get setup correctly as will the
* min & max ttls on the socket. The return value is
* irrelevant.
*/
ret = peer_ebgp_multihop_set (peer, MAXTTL);
if (ret != 0)
return ret;
}
else
{
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
peer->gtsm_hops = group->conf->gtsm_hops;
/* Calling ebgp multihop also resets the session.
* On restart, NHT will get setup correctly as will the
* min & max ttls on the socket. The return value is
* irrelevant.
*/
ret = peer_ebgp_multihop_set (peer, MAXTTL);
}
}
}
else
{
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
/* Post the first gtsm setup or if its ibgp, maxttl setting isn't
* necessary, just set the minttl.
*/
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
peer->gtsm_hops = group->conf->gtsm_hops;
peer->gtsm_hops = gtsm_hops;
/* Change setting of existing peer
* established then change value (may break connectivity)
* not established yet (teardown session and restart)
* no session then do nothing (will get handled by next connection)
*/
if (peer->status == Established)
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd,
MAXTTL + 1 - gtsm_hops);
if ((peer->status < Established) && peer->doppelganger &&
(peer->doppelganger->fd >= 0))
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
MAXTTL + 1 - gtsm_hops);
}
else
{
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
peer->gtsm_hops = group->conf->gtsm_hops;
/* Change setting of existing peer
* established then change value (may break connectivity)
* not established yet (teardown session and restart)
* no session then do nothing (will get handled by next connection)
*/
if (peer->fd >= 0 && peer->gtsm_hops != 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd,
MAXTTL + 1 - peer->gtsm_hops);
}
else if (peer->status < Established)
{
if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Min-ttl changed", peer->host);
bgp_session_reset(peer);
if ((peer->status < Established) && peer->doppelganger &&
(peer->doppelganger->fd >= 0))
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
MAXTTL + 1 - gtsm_hops);
}
}
}
@ -5564,7 +5608,7 @@ peer_ttl_security_hops_unset (struct peer *peer)
{
struct peer_group *group;
struct listnode *node, *nnode;
struct peer *opeer;
int ret = 0;
zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host);
@ -5574,14 +5618,23 @@ peer_ttl_security_hops_unset (struct peer *peer)
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);
/* Invoking ebgp_multihop_set will set the TTL back to the original
* value as well as restting the NHT and such. The session is reset.
*/
if (peer->sort == BGP_PEER_EBGP)
ret = peer_ebgp_multihop_unset (peer);
else
{
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
if (peer->status != Established && peer->doppelganger)
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
if ((peer->status < Established) && peer->doppelganger &&
(peer->doppelganger->fd >= 0))
sockopt_minttl (peer->su.sa.sa_family,
peer->doppelganger->fd, 0);
}
}
else
{
@ -5589,16 +5642,22 @@ peer_ttl_security_hops_unset (struct peer *peer)
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);
if (peer->sort == BGP_PEER_EBGP)
ret = peer_ebgp_multihop_unset (peer);
else
{
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
if (peer->status != Established && peer->doppelganger)
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
if ((peer->status < Established) && peer->doppelganger &&
(peer->doppelganger->fd >= 0))
sockopt_minttl (peer->su.sa.sa_family,
peer->doppelganger->fd, 0);
}
}
}
return peer_ebgp_multihop_unset (opeer);
return 0;
}
/*

View File

@ -496,6 +496,16 @@ sockopt_cork (int sock, int onoff)
#endif
}
/* For some crazy reason, our build doesn't seem to pick this up */
#ifdef GNU_LINUX
#ifndef IP_MINTTL
#define IP_MINTTL 21
#endif
#ifndef IPV6_MINHOPCNT
#define IPV6_MINHOPCNT 73
#endif
#endif
int
sockopt_minttl (int family, int sock, int minttl)
{

View File

@ -860,7 +860,8 @@ print_rnh (struct route_node *rn, struct vty *vty)
char buf[BUFSIZ];
rnh = rn->info;
vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
vty_out(vty, "%s%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
VTY_NEWLINE);
if (rnh->state)
{