mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 22:26:14 +00:00
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:
parent
4125bb6716
commit
e5cc509c34
@ -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)
|
bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
|
||||||
{
|
{
|
||||||
char buf[INET_ADDRSTRLEN];
|
char buf[INET_ADDRSTRLEN];
|
||||||
@ -164,6 +164,7 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
|
|||||||
__func__,
|
__func__,
|
||||||
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
|
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
|
||||||
errno);
|
errno);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (peer->gtsm_hops)
|
else if (peer->gtsm_hops)
|
||||||
@ -178,6 +179,7 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
|
|||||||
__func__,
|
__func__,
|
||||||
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
|
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
|
||||||
errno);
|
errno);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock,
|
ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock,
|
||||||
MAXTTL + 1 - peer->gtsm_hops);
|
MAXTTL + 1 - peer->gtsm_hops);
|
||||||
@ -187,8 +189,11 @@ bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
|
|||||||
__func__,
|
__func__,
|
||||||
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
|
inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
|
||||||
errno);
|
errno);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accept bgp connection. */
|
/* Accept bgp connection. */
|
||||||
@ -305,7 +310,10 @@ bgp_accept (struct thread *thread)
|
|||||||
peer_delete(peer1->doppelganger);
|
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,
|
peer = peer_create (&su, peer1->conf_if, peer1->bgp, peer1->local_as,
|
||||||
peer1->as, peer1->as_type, 0, 0);
|
peer1->as, peer1->as_type, 0, 0);
|
||||||
@ -453,7 +461,8 @@ bgp_connect (struct peer *peer)
|
|||||||
/* Set socket send buffer size */
|
/* Set socket send buffer size */
|
||||||
bgp_update_sock_send_buffer_size(peer->fd);
|
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_reuseaddr (peer->fd);
|
||||||
sockopt_reuseport (peer->fd);
|
sockopt_reuseport (peer->fd);
|
||||||
|
@ -29,5 +29,6 @@ extern int bgp_connect (struct peer *);
|
|||||||
extern int bgp_getsockname (struct peer *);
|
extern int bgp_getsockname (struct peer *);
|
||||||
|
|
||||||
extern int bgp_md5_set (struct peer *);
|
extern int bgp_md5_set (struct peer *);
|
||||||
|
extern int bgp_set_socket_ttl(struct peer *, int fd);
|
||||||
|
|
||||||
#endif /* _QUAGGA_BGP_NETWORK_H */
|
#endif /* _QUAGGA_BGP_NETWORK_H */
|
||||||
|
163
bgpd/bgpd.c
163
bgpd/bgpd.c
@ -3568,7 +3568,13 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
|
|||||||
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
||||||
{
|
{
|
||||||
if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP)
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -3580,8 +3586,11 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
|
|||||||
|
|
||||||
peer->ttl = group->conf->ttl;
|
peer->ttl = group->conf->ttl;
|
||||||
|
|
||||||
if (peer->fd >= 0)
|
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
|
||||||
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
|
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
|
||||||
|
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
|
||||||
|
else
|
||||||
|
bgp_session_reset(peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -3606,8 +3615,11 @@ peer_ebgp_multihop_unset (struct peer *peer)
|
|||||||
|
|
||||||
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
||||||
{
|
{
|
||||||
if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP)
|
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
|
||||||
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
|
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
|
||||||
|
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
|
||||||
|
else
|
||||||
|
bgp_session_reset(peer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3618,9 +3630,15 @@ peer_ebgp_multihop_unset (struct peer *peer)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
peer->ttl = 1;
|
peer->ttl = 1;
|
||||||
|
|
||||||
if (peer->fd >= 0)
|
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;
|
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
|
before actually applying the ttl-security rules. Cisco really made a
|
||||||
mess of this configuration parameter, and OpenBGPD got it right.
|
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))
|
if (is_ebgp_multihop_configured (peer))
|
||||||
return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
|
return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
|
||||||
|
|
||||||
/* specify MAXTTL on outgoing packets */
|
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
||||||
/* Routine handles iBGP peers correctly */
|
{
|
||||||
ret = peer_ebgp_multihop_set (peer, MAXTTL);
|
peer->gtsm_hops = gtsm_hops;
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
peer->gtsm_hops = gtsm_hops;
|
|
||||||
|
|
||||||
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
/* Calling ebgp multihop also resets the session.
|
||||||
{
|
* On restart, NHT will get setup correctly as will the
|
||||||
if (peer->fd >= 0)
|
* min & max ttls on the socket. The return value is
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->fd,
|
* irrelevant.
|
||||||
MAXTTL + 1 - gtsm_hops);
|
*/
|
||||||
if (peer->status != Established && peer->doppelganger)
|
ret = peer_ebgp_multihop_set (peer, MAXTTL);
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
|
|
||||||
MAXTTL + 1 - gtsm_hops);
|
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
|
else
|
||||||
{
|
{
|
||||||
group = peer->group;
|
/* Post the first gtsm setup or if its ibgp, maxttl setting isn't
|
||||||
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
|
* 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
|
if (peer->fd >= 0)
|
||||||
* established then change value (may break connectivity)
|
sockopt_minttl (peer->su.sa.sa_family, peer->fd,
|
||||||
* not established yet (teardown session and restart)
|
MAXTTL + 1 - gtsm_hops);
|
||||||
* no session then do nothing (will get handled by next connection)
|
if ((peer->status < Established) && peer->doppelganger &&
|
||||||
*/
|
(peer->doppelganger->fd >= 0))
|
||||||
if (peer->status == Established)
|
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)
|
if (peer->fd >= 0 && peer->gtsm_hops != 0)
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->fd,
|
sockopt_minttl (peer->su.sa.sa_family, peer->fd,
|
||||||
MAXTTL + 1 - peer->gtsm_hops);
|
MAXTTL + 1 - peer->gtsm_hops);
|
||||||
}
|
if ((peer->status < Established) && peer->doppelganger &&
|
||||||
else if (peer->status < Established)
|
(peer->doppelganger->fd >= 0))
|
||||||
{
|
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
|
||||||
if (bgp_debug_neighbor_events(peer))
|
MAXTTL + 1 - gtsm_hops);
|
||||||
zlog_debug ("%s Min-ttl changed", peer->host);
|
|
||||||
bgp_session_reset(peer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5564,7 +5608,7 @@ peer_ttl_security_hops_unset (struct peer *peer)
|
|||||||
{
|
{
|
||||||
struct peer_group *group;
|
struct peer_group *group;
|
||||||
struct listnode *node, *nnode;
|
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);
|
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
|
else
|
||||||
peer->gtsm_hops = 0;
|
peer->gtsm_hops = 0;
|
||||||
|
|
||||||
opeer = peer;
|
|
||||||
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
||||||
{
|
{
|
||||||
if (peer->fd >= 0)
|
/* Invoking ebgp_multihop_set will set the TTL back to the original
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
|
* 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)
|
if ((peer->status < Established) && peer->doppelganger &&
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
|
(peer->doppelganger->fd >= 0))
|
||||||
|
sockopt_minttl (peer->su.sa.sa_family,
|
||||||
|
peer->doppelganger->fd, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -5589,16 +5642,22 @@ peer_ttl_security_hops_unset (struct peer *peer)
|
|||||||
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
|
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
|
||||||
{
|
{
|
||||||
peer->gtsm_hops = 0;
|
peer->gtsm_hops = 0;
|
||||||
|
if (peer->sort == BGP_PEER_EBGP)
|
||||||
if (peer->fd >= 0)
|
ret = peer_ebgp_multihop_unset (peer);
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
|
else
|
||||||
|
{
|
||||||
|
if (peer->fd >= 0)
|
||||||
|
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
|
||||||
|
|
||||||
if (peer->status != Established && peer->doppelganger)
|
if ((peer->status < Established) && peer->doppelganger &&
|
||||||
sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
|
(peer->doppelganger->fd >= 0))
|
||||||
|
sockopt_minttl (peer->su.sa.sa_family,
|
||||||
|
peer->doppelganger->fd, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return peer_ebgp_multihop_unset (opeer);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -496,6 +496,16 @@ sockopt_cork (int sock, int onoff)
|
|||||||
#endif
|
#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
|
int
|
||||||
sockopt_minttl (int family, int sock, int minttl)
|
sockopt_minttl (int family, int sock, int minttl)
|
||||||
{
|
{
|
||||||
|
@ -860,7 +860,8 @@ print_rnh (struct route_node *rn, struct vty *vty)
|
|||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
rnh = rn->info;
|
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);
|
VTY_NEWLINE);
|
||||||
if (rnh->state)
|
if (rnh->state)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user