summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp.h10
-rw-r--r--bgpd/bgp_advertise.c8
-rw-r--r--bgpd/bgp_attr.c160
-rw-r--r--bgpd/bgp_common.h8
-rw-r--r--bgpd/bgp_connection.c53
-rw-r--r--bgpd/bgp_connection.h3
-rw-r--r--bgpd/bgp_debug.c26
-rw-r--r--bgpd/bgp_debug.h3
-rw-r--r--bgpd/bgp_fsm.c16
-rw-r--r--bgpd/bgp_main.c84
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--bgpd/bgp_msg_read.c3
-rw-r--r--bgpd/bgp_msg_write.c5
-rw-r--r--bgpd/bgp_network.c2
-rw-r--r--bgpd/bgp_nexthop.c2
-rw-r--r--bgpd/bgp_notification.c15
-rw-r--r--bgpd/bgp_notification.h17
-rw-r--r--bgpd/bgp_open.c59
-rw-r--r--bgpd/bgp_open_state.c36
-rw-r--r--bgpd/bgp_packet.c93
-rw-r--r--bgpd/bgp_packet.h5
-rw-r--r--bgpd/bgp_peer.c1932
-rw-r--r--bgpd/bgp_peer.h226
-rw-r--r--bgpd/bgp_peer_index.c87
-rw-r--r--bgpd/bgp_peer_index.h21
-rw-r--r--bgpd/bgp_route.c614
-rw-r--r--bgpd/bgp_route.h10
-rw-r--r--bgpd/bgp_session.c229
-rw-r--r--bgpd/bgp_session.h29
-rw-r--r--bgpd/bgp_table.c11
-rw-r--r--bgpd/bgp_vty.c110
-rw-r--r--bgpd/bgp_zebra.c2
-rw-r--r--bgpd/bgpd.c1106
-rw-r--r--bgpd/bgpd.h25
-rwxr-xr-xconfigure.ac2
-rw-r--r--lib/plist.c45
-rw-r--r--lib/qpnexus.c18
-rw-r--r--lib/qpnexus.h6
-rw-r--r--tests/bgp_capability_test.c2
39 files changed, 3082 insertions, 2003 deletions
diff --git a/bgpd/bgp.h b/bgpd/bgp.h
index 55cf0d2d..1016fe93 100644
--- a/bgpd/bgp.h
+++ b/bgpd/bgp.h
@@ -461,19 +461,19 @@ enum BGP_NOMC
enum BGP_NOMS
{
- BGP_NOMS_UNSPECIFIC = 0 /* If nothing else applies */
+ BGP_NOMS_UNSPECIFIC = 0 /* If nothing else applies */
};
enum BGP_NOMS_HEADER /* BGP_NOMC_HEADER subcodes */
{
- BGP_NOMS_H_NOT_SYNC = 1, /* Connection Not Synchronised */
+ BGP_NOMS_H_NOT_SYNC = 1, /* Connection Not Synchronised */
/* (Marker field not all = 1,'s !) */
- BGP_NOMS_H_BAD_LEN = 2, /* Bad Message Length */
+ BGP_NOMS_H_BAD_LEN = 2, /* Bad Message Length */
/* DATA: the length that failed */
- BGP_NOMS_H_BAD_TYPE = 3, /* Bad Message Type */
+ BGP_NOMS_H_BAD_TYPE = 3, /* Bad Message Type */
/* DATA: the message type objected to */
- BGP_NOMS_H_MAX = 3, /* max known subcode */
+ BGP_NOMS_H_MAX = 3, /* max known subcode */
} ;
enum BGP_NOMS_OPEN /* BGP_NOMC_OPEN subcodes */
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 552b2291..495d0fdc 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -231,7 +231,7 @@ bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
/* Add to list of adj_out stuff for the peer */
- adj->peer = peer_lock (peer);
+ adj->peer = bgp_peer_lock (peer);
adj_out_head = &(peer->adj_out_head[afi][safi]) ;
@@ -336,7 +336,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
else
peer->adj_out_head[afi][safi] = adj->route_next ;
- peer_unlock (peer);
+ bgp_peer_unlock (peer);
/* Unhook from bgp_node */
if (adj->adj_next)
@@ -379,7 +379,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
adj->attr = bgp_attr_intern (attr);
/* Add to list of adj in stuff for the peer */
- adj->peer = peer_lock (peer);
+ adj->peer = bgp_peer_lock (peer);
adj_in_head = &(peer->adj_in_head[rn->table->afi][rn->table->safi]) ;
@@ -420,7 +420,7 @@ bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
else
*adj_in_head = bai->route_next ;
- peer_unlock (peer);
+ bgp_peer_unlock (peer);
/* Unhook from bgp_node */
if (bai->adj_next)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index d79f25f2..7fc9749e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -718,10 +718,10 @@ bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"AS-Pathlimit attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -729,10 +729,10 @@ bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"AS-Pathlimit length, %u, is not 5", length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -760,10 +760,10 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"Origin attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -776,9 +776,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
length);
- bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, total);
return -1;
}
@@ -795,10 +795,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
attr->origin);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
- startp, total);
+ bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+ startp, total);
return -1;
}
@@ -824,10 +823,10 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"As-Path attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -841,9 +840,8 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
if (! attr->aspath)
{
zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return -1;
}
@@ -876,9 +874,8 @@ static int bgp_attr_aspath_check( struct peer *peer,
(peer_sort (peer) == 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,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return -1;
}
@@ -890,9 +887,8 @@ static int bgp_attr_aspath_check( struct peer *peer,
{
zlog (peer->log, LOG_ERR,
"%s incorrect first AS (must be %u)", peer->host, peer->as);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return -1;
}
}
@@ -941,10 +937,10 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"Origin attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
return -1;
}
@@ -954,7 +950,7 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
length);
- bgp_notify_send_with_data (peer,
+ bgp_peer_down_error_with_data (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
startp, total);
@@ -982,10 +978,10 @@ bgp_attr_med (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR,
"MED attribute length isn't four [%d]", length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, total);
return -1;
}
@@ -1030,9 +1026,9 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1059,9 +1055,8 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen,
length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1087,9 +1082,8 @@ bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
*as4_aggregator_as = stream_getl (peer->ibuf);
@@ -1145,9 +1139,8 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
zlog (peer->log, LOG_ERR,
"%s BGP not AS4 capable peer sent AS4_PATH but"
" no AS_PATH, cant do anything here", peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1247,9 +1240,8 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1271,9 +1263,8 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1511,10 +1502,10 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
{
/* Adjust startp to do not include flag value. */
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_UNREC_ATTR,
- startp, total);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_UNREC_ATTR,
+ startp, total);
return -1;
}
@@ -1584,9 +1575,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
peer->host,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1604,9 +1594,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
peer->host,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1626,9 +1615,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
"%s error BGP attribute type %d appears twice in a message",
peer->host, type);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1644,9 +1632,8 @@ 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);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1713,9 +1700,8 @@ 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);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return ret;
}
@@ -1734,9 +1720,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
PEER_CAP_AS4_USE(peer) ? "" : "NOT ") ;
} ;
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
}
@@ -1747,9 +1732,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
zlog (peer->log, LOG_WARNING,
"%s BGP attribute %s, length mismatch",
peer->host, LOOKUP (attr_str, type));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
return -1;
}
@@ -1829,10 +1813,10 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
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);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MISS_ATTR,
+ &type, 1);
return -1;
}
return 0;
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index d35d6da6..67d1afb0 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -134,10 +134,10 @@ enum bgp_peer_states
{
bgp_peer_min_state = 0,
- bgp_peer_sIdle = 1, /* session not yet established */
- bgp_peer_sEstablished = 2, /* session established */
- bgp_peer_sClearing = 3, /* Clearing routes */
- bgp_peer_sDeleted = 4, /* Deleted, linger until lock count == 0 */
+ bgp_peer_pIdle = 1, /* session not yet established */
+ bgp_peer_pEstablished = 2, /* session established */
+ bgp_peer_pClearing = 3, /* Clearing routes */
+ bgp_peer_pDeleting = 4, /* Deleting, lingers until lock count == 0 */
bgp_peer_max_state = 4
} ;
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index 41cde9a3..cdcfc10e 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -690,28 +690,65 @@ bgp_connection_stop(bgp_connection connection, int stop_writer)
} ;
/*------------------------------------------------------------------------------
- * Enable connection for accept()
+ * Enable connection/session for accept()
*
- * NB: requires the session to be LOCKED.
+ * NB: requires the session to be LOCKED
*/
extern void
bgp_connection_enable_accept(bgp_connection connection)
{
+ bgp_session session = connection->session ;
+
assert(connection->ordinal == bgp_connection_secondary) ;
- connection->session->index_entry->accept = connection ;
+ assert((session != NULL) && (session->active)) ;
+
+ session->accept = true ;
} ;
/*------------------------------------------------------------------------------
* Disable connection for accept() -- assuming still have session !
*
- * NB: requires the session to be LOCKED.
+ * NB: requires the session to be LOCKED
*/
extern void
bgp_connection_disable_accept(bgp_connection connection)
{
- bgp_session session = connection->session ;
- if (session != NULL)
- session->index_entry->accept = NULL ;
+ if (connection->session != NULL)
+ connection->session->accept = false ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * See if there is a connection which is ready to accept()
+ *
+ * Note that if there *is* a connection, then the session is active, and is not
+ * subject to the whim of the Routing Engine -- in particular it cannot be
+ * deleted !
+ *
+ * NB: this is *only* used in the BGP Engine. The session->active and
+ * session->accept flags are private variables, only set by the BGP Engine.
+ *
+ * NB: this is called under the Peer Index Mutex. The Routing Engine never
+ * deletes sessions while it holds the Peer Index Mutex, nor when the
+ * session->active is true.
+ *
+ * Only returns a connection if session->active -- so safe.
+ */
+extern bgp_connection
+bgp_connection_query_accept(bgp_session session)
+{
+ bgp_connection connection ;
+
+ if ((session != NULL) && session->active && session->accept)
+ {
+ connection = session->connections[bgp_connection_secondary] ;
+ assert(connection != NULL) ;
+ }
+ else
+ {
+ connection = NULL ;
+ } ;
+
+ return connection ;
} ;
/*------------------------------------------------------------------------------
@@ -830,7 +867,7 @@ bgp_connection_part_close(bgp_connection connection)
/* Turn off session->active (if still attached). */
if (session != NULL)
- session->active = 0 ;
+ session->active = false ;
/* Purge wbuff of all but current partly written message (if any) */
if (wb->p_in != wb->p_out) /* will be equal if buffer is empty */
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index 3d63edb7..58afc2ae 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -219,6 +219,9 @@ extern void
bgp_connection_disable_accept(bgp_connection connection) ;
extern bgp_connection
+bgp_connection_query_accept(bgp_session session) ;
+
+extern bgp_connection
bgp_connection_get_sibling(bgp_connection connection) ;
extern void
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 607bf824..684e9651 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -81,10 +81,10 @@ const int bgp_status_msg_max = bgp_fsm_last_state + 1 ;
const struct message bgp_peer_status_msg[] =
{
- { bgp_peer_sIdle, "Idle" },
- { bgp_peer_sEstablished, "Established" },
- { bgp_peer_sClearing, "Clearing" },
- { bgp_peer_sDeleted, "Deleted" },
+ { bgp_peer_pIdle, "Idle" },
+ { bgp_peer_pEstablished, "Established" },
+ { bgp_peer_pClearing, "Clearing" },
+ { bgp_peer_pDeleting, "Deleting" },
};
const int bgp_peer_status_msg_max = bgp_peer_max_state + 1 ;
@@ -254,7 +254,7 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
/* dump notify packet */
void
-bgp_notify_print(struct peer *peer, bgp_notify notification, bool sending)
+bgp_notify_print(struct peer *peer, bgp_notify notification)
{
const char* subcode_str ;
const char* code_str ;
@@ -328,15 +328,15 @@ bgp_notify_print(struct peer *peer, bgp_notify notification, bool sending)
/* Output the required logging */
if (log_neighbor_changes)
- zlog_info ("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s",
- sending ? "sent to" : "received from", peer->host,
- notification->code, notification->subcode,
- code_str, subcode_str, length, hex_form) ;
+ zlog_info("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s",
+ notification->received ? "received from" : "sent to", peer->host,
+ notification->code, notification->subcode,
+ code_str, subcode_str, length, hex_form) ;
else
- plog_debug (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
- peer->host, sending ? "sending" : "received",
- notification->code, notification->subcode,
- code_str, subcode_str, length, hex_form) ;
+ plog_debug(peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
+ peer->host, notification->received ? "received" : "sending",
+ notification->code, notification->subcode,
+ code_str, subcode_str, length, hex_form) ;
/* Release the */
if (alloc != NULL)
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 1d05cefb..2b9ca268 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -121,8 +121,7 @@ extern unsigned long term_bgp_debug_zebra;
extern const char *bgp_type_str[];
extern int bgp_dump_attr (struct peer *, struct attr *, char *, size_t);
-extern void bgp_notify_print (struct peer* peer, bgp_notify notification,
- bool sending);
+extern void bgp_notify_print (struct peer* peer, bgp_notify notification);
extern const struct message bgp_status_msg[];
extern const int bgp_status_msg_max;
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 9c323ffd..9df8a955 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -66,6 +66,20 @@
*
* The fsm action functions are called with the session locked.
*
+ * TODO: restore NSF
+ * TODO: track incoming connections while established
+ *
+ * To do this need to accept connection while established, then wait for
+ * OPEN. While waiting, the established connection may drop, and
+ * so the session restart, but with an incoming connection already
+ * in place.
+ *
+ * When OPEN arrives, for NSF should close any established connection
+ * and restart with the new one.
+ *
+ * Otherwise, if CollisionDetectEstablishedState option is set, should
+ * go through collision detection !
+ *
*------------------------------------------------------------------------------
* FSM "events" and Session "exceptions".
*
@@ -1932,6 +1946,8 @@ static bgp_fsm_action(bgp_fsm_error)
* Next state will be sIdle, except if is sEstablished, when will be sStopping.
*
* NB: requires the session LOCKED
+ *
+ * TODO: deal with: BGP_NOMC_OPEN/BGP_NOMS_O_OPTION & squash capabilities.
*/
static bgp_fsm_action(bgp_fsm_recv_nom)
{
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 0de28b9b..60b66533 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -75,20 +75,23 @@ static const struct option longopts[] =
{ "ignore_warnings", no_argument, NULL, 'I'},
{ 0 }
};
-/* Configuration file and directory. */
+/* Configuration file and directory. */
char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG;
-/* Route retain mode flag. */
-static int retain_mode = 0;
+/* Route retain mode flag. */
+static bool retain_mode = false;
+
+/* Have started terminating the program */
+static bool program_terminating = false ;
/* whether to ignore warnings in configuration file */
static bool config_ignore_warnings = false;
/* whether configured to run with qpthreads */
-static bool config_threaded = 0;
+static bool config_threaded = false ;
/* whether configured to run as an AS2 speaker */
-static bool config_as2_speaker = 0;
+static bool config_as2_speaker = false ;
/* Master of threads. */
struct thread_master *master;
@@ -483,11 +486,11 @@ int
main (int argc, char **argv)
{
char *p;
- int opt;
- int daemon_mode = 0;
- int dryrun = 0;
+ int opt;
+ bool daemon_mode = false ;
+ bool dryrun = false ;
char *progname;
- int tmp_port;
+ int tmp_port;
/* Set umask before anything for security */
umask (0027);
@@ -520,7 +523,7 @@ main (int argc, char **argv)
case 0:
break;
case 'd':
- daemon_mode = 1;
+ daemon_mode = true ;
break;
case 'f':
config_file = optarg;
@@ -551,7 +554,7 @@ main (int argc, char **argv)
vty_port = BGP_VTY_PORT;
break;
case 'r':
- retain_mode = 1;
+ retain_mode = true ;
break;
case 'l':
bm->address = optarg;
@@ -570,19 +573,19 @@ main (int argc, char **argv)
exit (0);
break;
case 'C':
- dryrun = 1;
+ dryrun = true ;
break;
case 'h':
usage (progname, 0);
break;
case 't':
- config_threaded = 1;
+ config_threaded = true ;
break;
case 'I':
- config_ignore_warnings = 1;
+ config_ignore_warnings = true ;
break ;
case '2':
- config_as2_speaker = 1;
+ config_as2_speaker = true ;
break ;
default:
usage (progname, 1);
@@ -716,6 +719,10 @@ routing_background(void)
return thread_dispatch_background(master) ;
}
+/*==============================================================================
+ * SIGHUP and SIGTERM
+ */
+
/*------------------------------------------------------------------------------
* SIGHUP: message sent to Routeing engine and the action it then takes.
*
@@ -726,14 +733,14 @@ sighup_enqueue(void)
{
mqueue_block mqb = mqb_init_new(NULL, sighup_action, NULL) ;
- mqueue_enqueue(routing_nexus->queue, mqb, 1) ;
+ mqueue_enqueue(routing_nexus->queue, mqb, mqb_priority) ;
}
/* dispatch a command from the message queue block */
static void
sighup_action(mqueue_block mqb, mqb_flag_t flag)
{
- if (flag == mqb_action)
+ if ((flag == mqb_action) && !program_terminating)
{
zlog_info ("bgpd restarting!");
@@ -753,6 +760,32 @@ sighup_action(mqueue_block mqb, mqb_flag_t flag)
}
/*------------------------------------------------------------------------------
+ * Foreground task to see if all peers have been deleted yet.
+ */
+static int
+program_terminate_if_all_peers_deleted(void)
+{
+ if (bm->peer_linger_count == 0)
+ {
+ /* ask remaining pthreads to die
+ *
+ * Note that qpn_terminate does nothing if it has been called once
+ * already.
+ */
+ if (qpthreads_enabled && routing_nexus != NULL)
+ qpn_terminate(routing_nexus);
+
+ if (qpthreads_enabled && bgp_nexus != NULL)
+ qpn_terminate(bgp_nexus);
+
+ if (cli_nexus != NULL)
+ qpn_terminate(cli_nexus) ;
+ } ;
+
+ return 0 ; /* nothing to do, really. */
+} ;
+
+/*------------------------------------------------------------------------------
* SIGTERM: message sent to Routeing engine and the action it then takes.
*/
static void
@@ -760,19 +793,26 @@ sigterm_enqueue(void)
{
mqueue_block mqb = mqb_init_new(NULL, sigterm_action, NULL) ;
- mqueue_enqueue(routing_nexus->queue, mqb, 1) ;
-}
+ mqueue_enqueue(routing_nexus->queue, mqb, mqb_priority) ;
+} ;
/* dispatch a command from the message queue block */
static void
sigterm_action(mqueue_block mqb, mqb_flag_t flag)
{
- if (flag == mqb_action)
+ if ((flag == mqb_action) && !program_terminating)
{
/* send notify to all peers, wait for all sessions to be disables
- * then terminate all pthreads */
+ * then terminate all pthreads
+ */
+ program_terminating = true ;
+
bgp_terminate(1, retain_mode);
+
+ qpn_add_hook_function(&routing_nexus->foreground,
+ program_terminate_if_all_peers_deleted) ;
}
mqb_free(mqb);
-}
+} ;
+
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 0489cf0f..983a4867 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -92,7 +92,7 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr,
u_char *tagpnt;
/* Check peer status. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
/* Make prefix_rd */
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index 664aed21..e0bbfef9 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -1420,8 +1420,9 @@ bgp_msg_notify_receive (bgp_connection connection, bgp_size_t body_size)
notification = bgp_notify_new_with_data(code, subcode,
stream_pnt(connection->ibuf), body_size - 2) ;
+ bgp_notify_set_received(notification) ;
- bgp_notify_print(connection->session->peer, notification, 0) ; /* Logging */
+ bgp_notify_print(connection->session->peer, notification) ; /* Logging */
bgp_fsm_notification_exception(connection, notification) ;
} ;
diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c
index 0323fa83..ee4a510c 100644
--- a/bgpd/bgp_msg_write.c
+++ b/bgpd/bgp_msg_write.c
@@ -85,14 +85,13 @@ extern int
bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
{
struct stream *s = connection->obuf ;
- int length;
+ int length;
++connection->session->stats.notify_out ;
assert(notification != NULL) ;
- /* Logging */
- bgp_notify_print(connection->session->peer, notification, 1) ;
+ bgp_notify_print(connection->session->peer, notification) ;
/* Make NOTIFY message header */
bgp_packet_set_marker (s, BGP_MSG_NOTIFY);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 77c89ff3..87f4f953 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -572,7 +572,7 @@ bgp_accept_action(qps_file qf, void* file_info)
bgp_connection connection ;
union sockunion su_remote ;
union sockunion su_local ;
- int exists ;
+ bool exists ;
int sock_fd ;
int err ;
int family ;
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index c72ca09f..de745007 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -438,7 +438,7 @@ bgp_scan (afi_t afi, safi_t safi)
/* Maximum prefix check */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
continue;
if (peer->afc[afi][SAFI_UNICAST])
diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c
index 2763f296..45bf99b7 100644
--- a/bgpd/bgp_notification.c
+++ b/bgpd/bgp_notification.c
@@ -54,6 +54,8 @@ bgp_notify_size(bgp_size_t size)
* Allocate and initialise new notification
*
* Can add data later if required.
+ *
+ * NB: returns a 'NOT received' notification.
*/
extern bgp_notify
bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode)
@@ -67,9 +69,10 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode)
/* Implicitly:
*
- * notification->size = 0
- * notification->length = 0
- * notification->data = NULL
+ * notification->received = false ;
+ * notification->size = 0
+ * notification->length = 0
+ * notification->data = NULL
*/
return notification ;
@@ -82,6 +85,8 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode)
* ...but pre-allocates at least the expected amount.
*
* May expect 0.
+ *
+ * NB: returns a 'NOT received' notification.
*/
extern bgp_notify
bgp_notify_new_expect(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
@@ -102,6 +107,8 @@ bgp_notify_new_expect(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
* Allocate and initialise new notification, complete with data
*
* Can specify an expected amount of data.
+ *
+ * NB: returns a 'NOT received' notification.
*/
extern bgp_notify
bgp_notify_new_with_data(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
@@ -228,6 +235,8 @@ bgp_notify_set_mov(bgp_notify* p_dst, bgp_notify* p_src)
/*==============================================================================
* Set new Code and Subcode and discard and data accumulated so far.
+ *
+ * NB: does not change the received state of the notification.
*/
extern bgp_notify
bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h
index a7e04501..20e96063 100644
--- a/bgpd/bgp_notification.h
+++ b/bgpd/bgp_notification.h
@@ -38,7 +38,10 @@ typedef unsigned char bgp_nom_code_t ;
typedef unsigned char bgp_nom_subcode_t ;
/*==============================================================================
+ * Structure for notification.
*
+ * Note that vast majority of notification handling concerns notifications that
+ * are *sent* to the far end. Occasionally a notification will be received.
*/
typedef struct bgp_notify* bgp_notify ;
@@ -47,6 +50,8 @@ struct bgp_notify
bgp_nom_code_t code ;
bgp_nom_subcode_t subcode ;
+ bool received ;
+
bgp_size_t length ;
bgp_size_t size ;
ptr_t data ;
@@ -166,6 +171,12 @@ bgp_notify_set_subcode(bgp_notify notification, bgp_nom_subcode_t subcode)
notification->subcode = subcode ;
} ;
+Inline void
+bgp_notify_set_received(bgp_notify notification)
+{
+ notification->received = true ;
+} ;
+
extern bgp_notify
bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
bgp_nom_subcode_t subcode) ;
@@ -193,6 +204,12 @@ bgp_notify_get_subcode(bgp_notify notification)
return (notification != NULL) ? notification->subcode : BGP_NOMS_UNSPECIFIC ;
} ;
+Inline bool
+bgp_notify_get_received(bgp_notify notification)
+{
+ return (notification != NULL) ? notification->received : false ;
+} ;
+
Inline bgp_size_t
bgp_notify_get_length(bgp_notify notification)
{
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7bcddca0..ab9acf63 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -58,7 +58,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
struct capability_mp_data mpc;
struct capability_header *hdr;
- if (peer == NULL || peer->session == NULL || peer->session->notification == NULL)
+ if ((peer == NULL) || (peer->session == NULL)
+ || (peer->session->notification == NULL))
return;
pnt = (char*)peer->session->notification->data;
@@ -254,8 +255,9 @@ 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);
+ peer->host, hdr->length, entry.num) ;
+ /* TODO: is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -497,7 +499,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
if (stream_get_getp(s) + 2 > end)
{
zlog_info ("%s Capability length error (< header)", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -509,7 +512,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
if (start + caphdr.length > end)
{
zlog_info ("%s Capability length error (< length)", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -539,7 +543,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
LOOKUP (capcode_str, caphdr.code),
caphdr.length,
(unsigned) cap_minsizes[caphdr.code]);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
/* we deliberately ignore unknown codes, see below */
@@ -628,9 +633,8 @@ bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
static int
bgp_auth_parse (struct peer *peer, size_t length)
{
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_AUTH_FAILURE);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_AUTH_FAILURE);
return -1;
}
@@ -752,7 +756,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
if (STREAM_READABLE(s) < 2)
{
zlog_info ("%s Option length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -764,7 +769,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
if (STREAM_READABLE (s) < opt_length)
{
zlog_info ("%s Option length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -785,9 +791,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
*capability = 1;
break;
default:
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_PARAM);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_PARAM);
ret = -1;
break;
}
@@ -807,10 +812,10 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
/* If Unsupported Capability exists. */
if (error != error_data)
{
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data, error - error_data);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL,
+ error_data, error - error_data);
return -1;
}
@@ -818,9 +823,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
peer. */
if (! strict_capability_same (peer))
{
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL);
return -1;
}
}
@@ -839,14 +843,13 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
if (error != error_data)
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data, error - error_data);
+ bgp_peer_down_error_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL,
+ error_data, error - error_data);
else
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
+ bgp_peer_down_error (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL);
return -1;
}
}
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
index 17f9ae36..c08160eb 100644
--- a/bgpd/bgp_open_state.c
+++ b/bgpd/bgp_open_state.c
@@ -293,12 +293,15 @@ bgp_open_state_afi_safi_cap(bgp_open_state state, unsigned index)
*
*/
-/* Received an open, update the peer's state */
+/* Received an open, update the peer's state
+ *
+ * NB: for safety, best to have the session locked -- though won't, in fact,
+ * change any of this information after the session is established.
+ */
void
bgp_peer_open_state_receive(bgp_peer peer)
{
- bgp_session session = peer->session;
- bgp_open_state open_send = session->open_send;
+ bgp_session session = peer->session;
bgp_open_state open_recv = session->open_recv;
qAFI_t afi;
qSAFI_t safi;
@@ -315,16 +318,13 @@ bgp_peer_open_state_receive(bgp_peer peer)
implementation MAY adjust the rate at which it sends KEEPALIVE
messages as a function of the Hold Time interval. */
- peer->v_holdtime =
- (open_recv->holdtime < open_send->holdtime)
- ? open_recv->holdtime
- : open_send->holdtime;
-
- peer->v_keepalive = peer->v_holdtime / 3;
-
- /* TODO: update session state as well? */
- session->hold_timer_interval = peer->v_holdtime ;
- session->keepalive_timer_interval = peer->v_keepalive ;
+ /* The BGP Engine sets the session's HoldTimer and KeepaliveTimer intervals
+ * to the values negotiated when the OPEN messages were exchanged.
+ *
+ * Take copies of that information.
+ */
+ peer->v_holdtime = session->hold_timer_interval ;
+ peer->v_keepalive = session->keepalive_timer_interval ;
/* Set remote router-id */
peer->remote_id.s_addr = open_recv->bgp_id;
@@ -404,12 +404,18 @@ bgp_peer_open_state_receive(bgp_peer peer)
if (open_recv->can_dynamic)
SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
- /* Graceful restart */
+ /* Graceful restart
+ *
+ * NB: appear not to care about open_recv->has_restarted !
+ */
+ if (open_recv->can_g_restart)
+ SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV) ;
+
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
{
qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi);
- if (peer->afc[afi][safi] && (qb & open_recv->can_g_restart))
+ if (peer->afc[afi][safi] && (qb & open_recv->can_preserve))
{
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
if (qb & open_recv->has_preserved)
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 71779567..62d76c60 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -764,35 +764,6 @@ bgp_open_send (struct peer *peer)
}
#endif
-/* Send BGP notify packet with data portion. */
-void
-bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
- u_char *data, size_t datalen)
-{
- bgp_notify notification;
- notification = bgp_notify_new_with_data(code, sub_code, data, datalen);
-
- /* peer reset cause */
- if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)
- {
- if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
- peer->last_reset = PEER_DOWN_USER_RESET;
- else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- else
- peer->last_reset = PEER_DOWN_NOTIFY_SEND;
- }
-
- bgp_peer_disable(peer, notification);
-}
-
-/* Send BGP notify packet. */
-void
-bgp_notify_send (struct peer *peer, u_char code, u_char sub_code)
-{
- bgp_notify_send_with_data (peer, code, sub_code, NULL, 0);
-}
-
/* Send route refresh message to the peer. */
void
@@ -1449,11 +1420,11 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
char attrstr[BUFSIZ] = "";
/* Status must be Established. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
{
zlog_err ("%s [FSM] Update packet received under status %s",
peer->host, LOOKUP (bgp_peer_status_msg, peer->state));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0);
return -1;
}
@@ -1476,8 +1447,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s [Error] Update packet error"
" (packet length is short for unfeasible length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1490,8 +1461,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s [Error] Update packet error"
" (packet unfeasible length overflow %d)",
peer->host, withdraw_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1518,8 +1489,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_warn ("%s [Error] Packet Error"
" (update packet is short for attribute length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1532,8 +1503,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_warn ("%s [Error] Packet Error"
" (update packet attribute length overflow %d)",
peer->host, attribute_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
+ bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1754,7 +1725,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* If peering is stopped due to some reason, do not generate BGP
event. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
/* Generate BGP event. */
@@ -1949,9 +1920,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
{
plog_err (peer->log, "%s [Error] BGP route refresh is not enabled",
peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE);
+ bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_BAD_MESTYPE);
return;
}
@@ -1961,7 +1931,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
plog_err (peer->log,
"%s [Error] Route refresh packet received under status %s",
peer->host, LOOKUP (bgp_status_msg, peer->status));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0);
return;
}
@@ -2003,7 +1973,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5)
{
zlog_info ("%s ORF route refresh length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return;
}
@@ -2130,7 +2100,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
if (pnt + 3 > end)
{
zlog_info ("%s Capability length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
action = *pnt;
@@ -2142,7 +2113,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
{
zlog_info ("%s Capability Action Value error %d",
peer->host, action);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -2154,7 +2126,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
if ((pnt + hdr->length + 3) > end)
{
zlog_info ("%s Capability length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ /* TODO: Is this the right notification ?? */
+ bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, 0);
return -1;
}
@@ -2200,16 +2173,20 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
{
peer->afc_recv[afi][safi] = 0;
peer->afc_nego[afi][safi] = 0;
+ bool completed ;
if (peer_active_nego (peer))
- bgp_clear_route_normal (peer, afi, safi);
+ completed = bgp_clear_routes (peer, afi, safi, false);
else
{
+ completed = true ;
/* TODO: only used for unit tests. Test will need fixing */
#if 0
BGP_EVENT_ADD (peer, BGP_Stop);
#endif
- }
+ } ;
+ /* if bgp_clear_routes does not complete. what do we do ? */
+ passert(completed) ;
}
}
else
@@ -2242,19 +2219,18 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
{
plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled",
peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE);
+ bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_BAD_MESTYPE);
return -1;
}
/* Status must be Established. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
{
plog_err (peer->log,
"%s [Error] Dynamic capability packet received under status %s",
peer->host, LOOKUP (bgp_status_msg, peer->state));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_peer_down_error (peer, BGP_NOTIFY_FSM_ERR, 0);
return -1;
}
@@ -2405,9 +2381,8 @@ bgp_read (struct thread *thread)
if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE))
&& ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE))
{
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_NOT_SYNC);
+ bgp_peer_down_error (peer, BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_NOT_SYNC);
goto done;
}
@@ -2508,7 +2483,7 @@ bgp_read (struct thread *thread)
{
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host);
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
return 0;
}
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index f0798846..6cf9a394 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -46,11 +46,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
extern int bgp_read (struct thread *);
extern int bgp_write (bgp_peer peer, struct stream*);
-extern void bgp_keepalive_send (struct peer *);
-extern void bgp_open_send (struct peer *);
-extern void bgp_notify_send (struct peer *, u_int8_t, u_int8_t);
-extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t,
- u_int8_t *, size_t);
extern void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int);
extern void bgp_capability_send (struct peer *, afi_t, safi_t, int, int);
extern void bgp_default_update_send (struct peer *, struct attr *,
diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c
index 18634fb0..2062c527 100644
--- a/bgpd/bgp_peer.c
+++ b/bgpd/bgp_peer.c
@@ -58,16 +58,6 @@
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
-/* prototypes */
-
-static int bgp_session_has_established(bgp_peer peer);
-static int bgp_session_has_stopped(bgp_peer peer);
-static int bgp_session_has_disabled(bgp_peer peer);
-static void bgp_uptime_reset (struct peer *peer);
-static int bgp_routeadv_timer (struct thread *thread);
-static int bgp_graceful_restart_timer_expire (struct thread *thread);
-static int bgp_graceful_stale_timer_expire (struct thread *thread);
-
/*==============================================================================
* This is the high level management of BGP Peers and peering conversations.
*
@@ -76,7 +66,7 @@ static int bgp_graceful_stale_timer_expire (struct thread *thread);
* Here we look after...
*
* * the peer state and the effects of changes in that state
- * *
+ *
* * timers for advertisements, graceful restart, ...
*
* The naming of peers/sessions and bgp_session_index
@@ -91,8 +81,122 @@ static int bgp_graceful_stale_timer_expire (struct thread *thread);
* The bgp_peer_index maps IP addresses to the peer, and hence to the session
* (if any exists and is active).
*
+ * [To support multi-instance BGP, might be nice to use the "update source"
+ * address as part of the name of a peer. But that is another story.]
+ *
+ *------------------------------------------------------------------------------
+ * The Peer State.
+ *
+ * The peer has a small number of states. Where there is a session, its state
+ * is a sub-state of the main peer state.
+ *
+ * The states of a peer are as follows:
+ *
+ * 1. bgp_peer_pIdle
+ *
+ * All peers start in this state.
+ *
+ * This is the case when:
+ *
+ * a. peer is administratively down/disabled/deactivated
+ *
+ * b. waiting for route flap or other such timer before reawakening.
+ *
+ * c. waiting for previous session to be closed -- in BGP Engine
+ *
+ * d. waiting for session to establish -- in BGP Engine
+ *
+ * The session states relate to the above as follows:
+ *
+ * sIdle, sDisabled or no session at all -- (a) or (b)
+ *
+ * sEnabled -- (d)
+ *
+ * sEstablished -- IMPOSSIBLE
+ *
+ * sLimping -- (c)
+ *
+ * Only when the peer is none of (a), (b) or (c) can a session be enabled
+ * and the session move to (d), sEnabled. So changes either in the state
+ * of the peer or in the state of the session have to check whether it
+ * is time to:
+ *
+ * 1. enable a new session
+ *
+ * 2. disable a session which has yet to reach sEstablished, but is
+ * now no longer correctly configured, or the like.
+ *
+ * 2. bgp_peer_pEstablished
+ *
+ * Reaches this state from pIdle when a session becomes established.
+ *
+ * This can only be the case when the session is sEstablished.
+ *
+ * If the session is stopped for any reason, issues a Disable request to
+ * the BGP Engine:
+ *
+ * peer -> pClearing
+ * session -> sLimping
+ *
+ * 3. bgp_peer_pClearing
+ *
+ * Reaches this state from pEstablished *only*, as above.
+ *
+ * In this state the session can only be:
+ *
+ * sLimping -- session disable has been sent to the BGP Engine.
+ * sDisabled -- session has been disabled by the BGP Engine
+ *
+ * Tidies up the peer, including clearing routes etc. Once the peer is
+ * completely tidy:
+ *
+ * peer -> pIdle
+ *
+ * On entry to pClearing the session will be sLimping, on exit it may be
+ * still sLimping, or have advanced to sDisabled.
+ *
+ * NB: while in pClearing the peer's routes and RIBs are being processed.
+ * All other parts of the peer may be modified... but mindful of the
+ * "background" task which is yet to complete.
+ *
+ * 4. bgp_peer_pDeleted
+ *
+ * This is an exotic state, reached only when a peer is being completely
+ * deleted.
+ *
+ * This state may be reached from any of the above.
+ *
+ * If there is an active session, it will be sLimping. When advances to
+ * sDisabled it will be deleted.
+ *
+ * The remaining tasks are to clear out routes, dismantle the peer
+ * structure and delete it. While that is happening, the peer is in this
+ * state.
*/
+/* prototypes */
+
+static void bgp_session_has_established(bgp_session session);
+static void bgp_session_has_stopped(bgp_session session);
+static void bgp_session_has_disabled(bgp_session session);
+static void bgp_uptime_reset (struct peer *peer);
+static void bgp_peer_stop (struct peer *peer, bool nsf) ;
+static void bgp_peer_reset_idle(struct peer *peer) ;
+static void bgp_peer_down_notify(bgp_peer peer, peer_down_t why_down,
+ bgp_notify notification) ;
+static void bgp_peer_shutdown(bgp_peer peer) ;
+static bgp_notify bgp_peer_map_peer_down(peer_down_t why_down) ;
+static peer_down_t bgp_peer_map_notification(bgp_notify notification) ;
+static void bgp_peer_free (struct peer *peer) ;
+static void bgp_peer_change_status (bgp_peer peer, bgp_peer_state_t new_state);
+static void bgp_peer_timers_set (struct peer *peer) ;
+static int bgp_routeadv_timer (struct thread *thread);
+static int bgp_graceful_restart_timer_expire (struct thread *thread);
+static void bgp_graceful_restart_timer_cancel (struct peer* peer) ;
+static int bgp_graceful_stale_timer_expire (struct thread *thread);
+static void bgp_graceful_stale_timer_cancel (struct peer* peer) ;
+
+
/*==============================================================================
* Deal with change in session state -- mqueue_action function.
*
@@ -106,17 +210,16 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
{
struct bgp_session_event_args * args = mqb_get_args(mqb) ;
- bgp_session session = mqb_get_arg0(mqb) ;
- bgp_peer peer = session->peer ;
+ bgp_session session = mqb_get_arg0(mqb) ;
if (flag == mqb_action)
{
- BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ /* Pull stuff into Routing Engine *private* fields in the session */
session->event = args->event ; /* last event */
bgp_notify_set(&session->notification, args->notification) ;
/* if any sent/received */
- session->err = args->err ; /* errno, if any */
+ session->err = args->err ; /* errno, if any */
session->ordinal = args->ordinal ; /* primary/secondary connection */
switch(args->event)
@@ -132,14 +235,18 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
if (session->state == bgp_session_sLimping)
break ;
- bgp_session_has_established(peer);
+ bgp_session_has_established(session);
break ;
/* If now Disabled, then the BGP Engine is acknowledging the a
* session disable, and the session is now disabled.
+ *
+ * BEWARE: this may be the last thing that happens to the session
+ * and/or the related peer -- which may be deleted inside
+ * bgp_session_has_disabled().
*/
case bgp_session_eDisabled:
- bgp_session_has_disabled(peer);
+ bgp_session_has_disabled(session);
break ;
/* If now Stopped, then for some reason the BGP Engine has either
@@ -152,11 +259,9 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
break ;
if (args->stopped)
- bgp_session_has_stopped(peer);
+ bgp_session_has_stopped(session) ;
break ;
} ;
-
- BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
}
else
bgp_notify_free(args->notification) ;
@@ -164,41 +269,49 @@ bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag)
mqb_free(mqb) ;
}
-/* BGP Session has been Established.
- *
- * NB: holding the session structure mutex.
- *
- * Send keepalive packet then make first update information.
+/*------------------------------------------------------------------------------
+ * BGP Session has been Established.
*/
-static int
-bgp_session_has_established(bgp_peer peer)
+static void
+bgp_session_has_established(bgp_session session)
{
afi_t afi;
safi_t safi;
- int nsf_af_count = 0;
+ int nsf_af_count ;
- bgp_session session = peer->session ;
+ bgp_peer peer = session->peer ;
+ assert(peer->session == session) ; /* Safety first */
+ /* Session state change -- Routing Engine private fields */
assert(session->state == bgp_session_sEnabled) ;
session->state = bgp_session_sEstablished ;
session->flow_control = BGP_XON_REFRESH; /* updates can be sent */
- peer_change_status (peer, bgp_peer_sEstablished);
- /* update peer state from received open */
- bgp_peer_open_state_receive(peer);
+ /* Peer state change.
+ *
+ * This stops all timers other than the Graceful Stale Timer.
+ */
+ bgp_peer_change_status (peer, bgp_peer_pEstablished);
+
+ /* Extracting information from shared fields. */
+ BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- /* get the local and remote addresses, and set the nexthop. */
+ bgp_peer_open_state_receive(peer);
sockunion_set_dup(&peer->su_local, session->su_local) ;
sockunion_set_dup(&peer->su_remote, session->su_remote) ;
+
+ BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ /* Install next hop, as required. */
bgp_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer) ;
/* Reset capability open status flag. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
- /* Clear last notification data. */
+ /* Clear last notification data -- Routing Engine private field */
bgp_notify_unset(&(peer->session->notification));
/* Clear start timer value to default. */
@@ -212,17 +325,29 @@ bgp_session_has_established(bgp_peer peer)
if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
- /* graceful restart */
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ /* graceful restart */
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) ;
+
+ nsf_af_count = 0 ;
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
{
+ /* If the afi/safi has been negotiated, and have received Graceful
+ * Restart capability, and is Restarting, and will Gracefully Restart
+ * the afi/safi, then....
+ */
if (peer->afc_nego[afi][safi]
&& CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)
&& CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV))
{
+ /* If have held onto routes for this afi/safi but forwarding has
+ * not been preserved, then clean out the stale routes.
+ *
+ * Set NSF for this address family for next time.
+ */
if (peer->nsf[afi][safi]
- && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV))
+ && ! CHECK_FLAG (peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV))
bgp_clear_stale_route (peer, afi, safi);
peer->nsf[afi][safi] = 1;
@@ -230,6 +355,7 @@ bgp_session_has_established(bgp_peer peer)
}
else
{
+ /* Remove stale routes, if any for this afi/safi */
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
peer->nsf[afi][safi] = 0;
@@ -241,28 +367,9 @@ bgp_session_has_established(bgp_peer peer)
else
{
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
- if (peer->t_gr_stale)
- {
- BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
+ bgp_graceful_stale_timer_cancel(peer) ;
}
- if (peer->t_gr_restart)
- {
- BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart timer stopped", peer->host);
- }
-
-#ifdef HAVE_SNMP
- bgpTrapEstablished (peer);
-#endif /* HAVE_SNMP */
-
- /* Reset uptime, send keepalive, send current table. */
- bgp_uptime_reset (peer);
-
/* Send route-refresh when ORF is enabled */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
@@ -284,145 +391,268 @@ bgp_session_has_established(bgp_peer peer)
|| CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
+ /* Reset uptime, send current table. */
+ bgp_uptime_reset (peer);
+
bgp_announce_route_all (peer);
BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
- return 0;
+#ifdef HAVE_SNMP
+ bgpTrapEstablished (peer);
+#endif /* HAVE_SNMP */
}
/*------------------------------------------------------------------------------
- * State change to sLimping, session mutex locked
+ * BGP Session has stopped of its own accord -> disable the peer & session.
*
* The BGP Engine has signalled that it has stopped the session. Response to
* that is to tell it to disable the session, and then wait in sLimping state
- * until the BGP Engine acknowledges the disable request.
+ * until the BGP Engine completes the disable request and signals that.
+ *
+ * TODO: session stopped because we stopped it or because the other end did ?
+ * TODO: restore NSF !!
*/
-static int
-bgp_session_has_stopped(bgp_peer peer)
+static void
+bgp_session_has_stopped(bgp_session session)
{
- bgp_session session = peer->session ;
+ peer_down_t why_down ;
- assert(bgp_session_is_active(session)) ;
- bgp_peer_disable(peer, NULL);
- /* TODO: needs to deal with NOTIFICATION, if any ?? */
+ bgp_peer peer = session->peer ;
+ assert(peer->session == session) ; /* Safety first */
- return 0;
-}
+ assert(bgp_session_is_active(session)) ; /* "confused" if not */
+
+ if (session->state == bgp_session_sEstablished)
+ {
+ /* This code has been moved from where it was, in bgp_write */
+ /* TODO: not clear whether v_start handling is still correct */
+ peer->v_start *= 2;
+ if (peer->v_start >= (60 * 2))
+ peer->v_start = (60 * 2);
+ } ;
+
+ if (session->notification == NULL)
+ why_down = PEER_DOWN_CLOSE_SESSION ;
+ else
+ {
+ if (session->notification->received)
+ why_down = PEER_DOWN_NOTIFY_RECEIVED ;
+ else
+ why_down = bgp_peer_map_notification(session->notification) ;
+ } ;
+
+ bgp_peer_down_notify(peer, why_down, session->notification) ;
+} ;
/*------------------------------------------------------------------------------
- * State change to sDisabled, session mutex locked
+ * BGP Session is now disabled -> can now move peer on to next state.
*
- * The BGP Engine has acknowledged the disable request.
+ * The BGP Engine has closed the session in response to a disable request, and
+ * no longer has an interest in it, and has signalled that.
*/
-static int
-bgp_session_has_disabled(bgp_peer peer)
+static void
+bgp_session_has_disabled(bgp_session session)
{
- bgp_session session = peer->session;
+ bgp_peer peer = session->peer ;
+ assert(peer->session == session) ; /* Safety first */
assert(session->state == bgp_session_sLimping) ;
session->state = bgp_session_sDisabled ;
- /* Immediately discard any other messages for this session. */
+ /* Immediately discard any other messages for this session. */
mqueue_revoke(routing_nexus->queue, session) ;
- /* does the peer need to be re-enabled? */
- if (session->defer_enable || peer->state == bgp_peer_sIdle)
- {
- session->defer_enable = 0;
- bgp_peer_enable(peer);
- }
- else if (peer->state == bgp_peer_sEstablished)
- {
- /* disable the peer */
- bgp_peer_stop(peer);
- peer_change_status(peer, bgp_peer_sClearing);
- bgp_clear_route_all(peer);
- }
-
- /* if the program is terminating then see if this was the last session
- * and if so ... die ....
+ /* If the session is marked "delete_me", do that.
+ *
+ * Otherwise, Old session now gone, so re-enable peer if now possible.
*/
- program_terminate_if_all_disabled();
- return 0;
-}
+ if (session->delete_me)
+ bgp_session_delete(peer) ; /* NB: this may also delete the peer. */
+ else
+ bgp_peer_enable(peer);
+} ;
-/* Administrative BGP peer stop event. */
-/* May be called multiple times for the same peer */
-int
-bgp_peer_stop (struct peer *peer)
+/*------------------------------------------------------------------------------
+ * Administrative BGP peer stop event -- stop pEstablished peer.
+ *
+ * MUST be pEstablished.
+ *
+ * Changes to pClearing and sets off to clear down all routes etc, subject to
+ * the required NSF.
+ *
+ * On exit the peer will be:
+ *
+ * - pIdle if the clearing of routes etc completed immediately.
+ *
+ * - pClearing if further work for clearing of routes has been scheduled
+ * for later.
+ *
+ * NB: Leaves any Max Prefix Timer running.
+ *
+ * Starts Graceful Restart and Stale Route timers iff NSF and at least one
+ * afi/safi is enabled for NSF.
+ */
+static void
+bgp_peer_stop (struct peer *peer, bool nsf)
{
- afi_t afi;
- safi_t safi;
- char orf_name[BUFSIZ];
+ bool cleared ;
- /* Can't do this in Clearing; events are used for state transitions */
- if (peer->state != bgp_peer_sClearing)
- {
- /* Delete all existing events of the peer */
- BGP_EVENT_FLUSH (peer);
- }
+ assert(peer->state == bgp_peer_pEstablished) ;
- /* Increment Dropped count. */
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->dropped++;
+ /* Change state to pClearing.
+ *
+ * Turns off all timers.
+ */
+ bgp_peer_change_status(peer, bgp_peer_pClearing) ;
- /* bgp log-neighbor-changes of neighbor Down */
- if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
- zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
- peer_down_str [(int) peer->last_reset]);
+ peer->dropped++ ;
+ peer->resettime = time (NULL) ;
- /* graceful restart */
- if (peer->t_gr_stale)
- {
- BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- {
- if (BGP_DEBUG (events, EVENTS))
- {
- zlog_debug ("%s graceful restart timer started for %d sec",
- peer->host, peer->v_gr_restart);
- zlog_debug ("%s graceful restart stalepath timer started for %d sec",
- peer->host, peer->bgp->stalepath_time);
- }
- BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
- peer->v_gr_restart);
- BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
- peer->bgp->stalepath_time);
- }
- else
- {
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+ /* bgp log-neighbor-changes of neighbor Down */
+ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
+ zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
+ peer_down_str [(int) peer->last_reset]);
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- peer->nsf[afi][safi] = 0;
+ /* Clear out routes, with NSF if required.
+ *
+ * Sets PEER_STATUS_NSF_WAIT iff NSF and at least one afi/safi is enabled
+ * for NSF. Clears PEER_STATUS_NSF_WAIT otherwise.
+ */
+ cleared = bgp_clear_all_routes (peer, nsf) ;
+
+ /* graceful restart */
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ {
+ if (BGP_DEBUG (events, EVENTS))
+ {
+ zlog_debug ("%s graceful restart timer started for %d sec",
+ peer->host, peer->v_gr_restart);
+ zlog_debug ("%s graceful restart stalepath timer started for %d sec",
+ peer->host, peer->bgp->stalepath_time);
}
+ BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
+ peer->v_gr_restart);
+ BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
+ peer->bgp->stalepath_time);
+ } ;
- /* set last reset time */
- peer->resettime = time (NULL);
- /* Reset uptime. */
- bgp_uptime_reset (peer);
+ /* Reset uptime. */
+ bgp_uptime_reset (peer);
#ifdef HAVE_SNMP
- bgpTrapBackwardTransition (peer);
+ bgpTrapBackwardTransition (peer);
#endif /* HAVE_SNMP */
- /* Reset uptime. */
- bgp_uptime_reset (peer);
+ /* Reset peer synctime */
+ peer->synctime = 0;
- /* Reset peer synctime */
- peer->synctime = 0;
- }
+ /* If completed the clearing of routes, then can now go pIdle */
+ if (cleared)
+ bgp_peer_change_status(peer, bgp_peer_pIdle) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Clear out any stale routes, cancel any Graceful Restart timers.
+ *
+ * NB: may still be pClearing from when peer went down leaving these stale
+ * routes.
+ *
+ * NB: assumes clearing stale routes will complete immediately !
+ */
+static void
+bgp_peer_clear_all_stale_routes (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route (peer, afi, safi);
+
+ bgp_graceful_restart_timer_cancel(peer) ;
+ bgp_graceful_stale_timer_cancel(peer) ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+} ;
+
+/*------------------------------------------------------------------------------
+ * If waiting for NSF peer to come back, stop now.
+ *
+ * When a session stops -- see bgp_peer_stop(), above -- the peer is set
+ * PEER_STATUS_NSF_WAIT iff there are now stale routes in the table, waiting
+ * for peer to come back.
+ *
+ * This function terminates that wait and clears out any stale routes, and
+ * cancels any timers.
+ *
+ * Also clears down all NSF flags.
+ *
+ * If is PEER_STATUS_NSF_WAIT, MUST be pIdle or pClearing.
+ *
+ * NB: may still be pClearing from when peer went down leaving these stale
+ * routes.
+ *
+ * NB: assumes clearing stale routes will complete immediately !
+ */
+static void
+bgp_peer_nsf_stop (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
+ {
+ assert( (peer->state == bgp_peer_pIdle)
+ || (peer->state == bgp_peer_pClearing) ) ;
+
+ bgp_peer_clear_all_stale_routes (peer) ;
+ } ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+ peer->nsf[afi][safi] = 0;
+} ;
- /* Stop all timers. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
+/*------------------------------------------------------------------------------
+ * Set the PEER_FLAG_SHUTDOWN flag and also:
+ *
+ * - turn off any NSF and related timers.
+ *
+ * - turn off any Max Prefix overflow and related timers.
+ */
+static void
+bgp_peer_shutdown(struct peer *peer)
+{
+ SET_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) ;
+
+ bgp_maximum_prefix_cancel_timer(peer) ;
+
+ bgp_peer_nsf_stop (peer) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Reset state as peer goes to pIdle.
+ *
+ * This tidies things up, ready for session to be enabled again.
+ *
+ * NB: can be called any number of times... either to tidy up or to prepare
+ * for session to be enabled.
+ */
+static void
+bgp_peer_reset_idle(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+ char orf_name[BUFSIZ];
+
+ assert(peer->state == bgp_peer_pIdle) ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE) ;
peer->cap = 0 ;
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
@@ -430,8 +660,9 @@ bgp_peer_stop (struct peer *peer)
{
/* Reset all negotiated variables */
peer->afc_nego[afi][safi] = 0;
- peer->afc_adv[afi][safi] = 0;
+ peer->afc_adv[afi][safi] = 0;
peer->afc_recv[afi][safi] = 0;
+ peer->nsf[afi][safi] = 0;
/* peer address family capability flags*/
peer->af_cap[afi][safi] = 0;
@@ -445,7 +676,7 @@ bgp_peer_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);
- }
+ } ;
/* Reset keepalive and holdtime */
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
@@ -457,283 +688,38 @@ bgp_peer_stop (struct peer *peer)
{
peer->v_keepalive = peer->bgp->default_keepalive;
peer->v_holdtime = peer->bgp->default_holdtime;
- }
-
-#if 0
- /* Reset prefix count */
- peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
- peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
- peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
- peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
- peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
-#endif
-
- return 0;
-}
-
-/*------------------------------------------------------------------------------
- * When a bgp_clear_route_all completes, this is called to move the peer state
- * on, if required.
- */
-extern void
-bgp_peer_clearing_completed(struct peer *peer)
-{
- /* Flush the event queue and ensure the peer is shut down */
- bgp_peer_stop(peer);
- BGP_EVENT_FLUSH (peer);
-
- if (peer->state == bgp_peer_sClearing)
- {
- peer_change_status (peer, bgp_peer_sIdle);
- /* enable peer if required */
- bgp_peer_enable(peer);
- }
+ } ;
} ;
-#if 0
-/* Stop all timers for the given peer
+/*------------------------------------------------------------------------------
+ * Allocate new peer object, implicitly locked.
*/
-static void
-bgp_peer_timers_stop(bgp_peer peer)
-{
- BGP_TIMER_OFF(peer->t_asorig) ;
- BGP_TIMER_OFF(peer->t_routeadv) ;
-
- BGP_TIMER_OFF (peer->t_gr_restart);
- BGP_TIMER_OFF (peer->t_gr_stale);
- BGP_TIMER_OFF (peer->t_pmax_restart);
-} ;
-#endif
-
-static void
-bgp_timer_set (struct peer *peer)
-{
- switch (peer->state)
- {
- case bgp_peer_sIdle:
- /* First entry point of peer's finite state machine. In Idle
- status start timer is on unless peer is shutdown or peer is
- inactive. All other timer must be turned off */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
-#if 0
- case Connect:
- /* After start timer is expired, the peer moves to Connnect
- status. Make sure start timer is off and connect timer is
- on. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
- case Active:
- /* Active is waiting connection from remote peer. And if
- connect timer is expired, change status to Connect. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
- case OpenSent:
- /* OpenSent status. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-
- case OpenConfirm:
- /* OpenConfirm status. */
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
-#endif
-
- case bgp_peer_sEstablished:
- /* In Established status start and connect timer is turned
- off. */
- BGP_TIMER_OFF (peer->t_asorig);
- break;
- case bgp_peer_sDeleted:
- BGP_TIMER_OFF (peer->t_gr_restart);
- BGP_TIMER_OFF (peer->t_gr_stale);
- BGP_TIMER_OFF (peer->t_pmax_restart);
- case bgp_peer_sClearing:
- BGP_TIMER_OFF (peer->t_asorig);
- BGP_TIMER_OFF (peer->t_routeadv);
- break;
- default:
- assert(0);
- }
-}
-
-static int
-bgp_routeadv_timer (struct thread *thread)
-{
- struct peer *peer;
- uint32_t jittered ;
- uint32_t jitter ;
-
- peer = THREAD_ARG (thread);
- peer->t_routeadv = NULL;
-
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG,
- "%s [FSM] Timer (routeadv timer expire)",
- peer->host);
-
- peer->synctime = time (NULL);
-
- bgp_write(peer, NULL);
-
- /* Apply +/- 10% jitter to the route advertise timer.
- *
- * The time is in seconds, so for anything less than 10 seconds this forced
- * to be +/- 1 second.
- */
- jittered = jitter = peer->v_routeadv ;
- if (jitter < 10)
- jitter = 10 ;
- jittered = (jittered * 90) + (rand() % (jitter * 20)) ; /* jitter is +/-10% */
- jittered = (jittered + 50) / 100 ;
-
- /* TODO: move this to the Routeing Engine qtimer pile. */
- BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, jittered) ;
-
- return 0;
-}
-
-/* Reset bgp update timer */
-static void
-bgp_uptime_reset (struct peer *peer)
-{
- peer->uptime = time (NULL);
-}
-
-/* BGP Peer Down Cause */
-const char *peer_down_str[] =
-{
- "",
- "Router ID changed",
- "Remote AS changed",
- "Local AS change",
- "Cluster ID changed",
- "Confederation identifier changed",
- "Confederation peer changed",
- "RR client config change",
- "RS client config change",
- "Update source change",
- "Address family activated",
- "Admin. shutdown",
- "User reset",
- "BGP Notification received",
- "BGP Notification send",
- "Peer closed the session",
- "Neighbor deleted",
- "Peer-group add member",
- "Peer-group delete member",
- "Capability changed",
- "Passive config change",
- "Multihop config change",
- "NSF peer closed the session"
-};
-
-static int
-bgp_graceful_restart_timer_expire (struct thread *thread)
-{
- struct peer *peer;
- afi_t afi;
- safi_t safi;
-
- peer = THREAD_ARG (thread);
- peer->t_gr_restart = NULL;
-
- /* NSF delete stale route */
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- if (peer->nsf[afi][safi])
- bgp_clear_stale_route (peer, afi, safi);
-
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- BGP_TIMER_OFF (peer->t_gr_stale);
-
- if (BGP_DEBUG (events, EVENTS))
- {
- zlog_debug ("%s graceful restart timer expired", peer->host);
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
-
- bgp_timer_set (peer);
-
- return 0;
-}
-
-static int
-bgp_graceful_stale_timer_expire (struct thread *thread)
-{
- struct peer *peer;
- afi_t afi;
- safi_t safi;
-
- peer = THREAD_ARG (thread);
- peer->t_gr_stale = NULL;
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
-
- /* NSF delete stale route */
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- if (peer->nsf[afi][safi])
- bgp_clear_stale_route (peer, afi, safi);
-
- return 0;
-}
-
-#if 0
-/* BGP peer is stopped by the error. */
-static int
-bgp_stop_with_error (struct peer *peer)
-{
- /* Double start timer. */
- peer->v_start *= 2;
-
- /* Overflow check. */
- if (peer->v_start >= (60 * 2))
- peer->v_start = (60 * 2);
-
- bgp_stop (peer);
-
- return 0;
-}
-#endif
-
-/* Allocate new peer object, implicitly locked. */
struct peer *
-peer_new (struct bgp *bgp)
+bgp_peer_new (struct bgp *bgp)
{
afi_t afi;
safi_t safi;
struct peer *peer;
struct servent *sp;
- /* bgp argument is absolutely required */
+ /* bgp argument is absolutely required */
assert (bgp);
- if (!bgp)
- return NULL;
+ bgp_lock (bgp);
- /* Allocate new peer. */
+ /* Allocate new peer. */
peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
/* Set default value. */
- peer->v_start = BGP_INIT_START_TIMER;
+ peer->v_start = BGP_INIT_START_TIMER;
peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
- peer->state = bgp_peer_sIdle;
- peer->ostate = bgp_peer_sIdle;
- peer->weight = 0;
- peer->password = NULL;
- peer->bgp = bgp;
- peer = peer_lock (peer); /* initial reference */
- bgp_lock (bgp);
+ peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
+ peer->state = bgp_peer_pIdle;
+ peer->ostate = bgp_peer_pIdle;
+ peer->weight = 0;
+ peer->password = NULL;
+ peer->bgp = bgp;
+
+ peer = bgp_peer_lock (peer); /* initial reference */
/* Set default flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
@@ -762,32 +748,41 @@ peer_new (struct bgp *bgp)
return peer;
}
-/* Create new BGP peer. */
+/*------------------------------------------------------------------------------
+ * Create new BGP peer -- if an AFI/SAFI is given, activate & enable for that.
+ *
+ * Peer starts in pIdle state.
+ *
+ * This is creating a PEER_STATUS_REAL_PEER, which is placed on the bgp->peer
+ * list.
+ */
struct peer *
-peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
- as_t remote_as, afi_t afi, safi_t safi)
+bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
+ as_t remote_as, afi_t afi, safi_t safi)
{
- int active;
struct peer *peer;
+ bool enable = (afi != 0) && (safi != 0) ;
+
+ /* TODO: should bgp_peer_new() set state pNull ?? */
+ peer = bgp_peer_new (bgp); /* sets peer->state == pIdle */
- peer = peer_new (bgp);
- peer->su = *su;
- peer->local_as = local_as;
- peer->as = remote_as;
- peer->local_id = bgp->router_id;
- peer->v_holdtime = bgp->default_holdtime;
+ peer->su = *su;
+ peer->local_as = local_as;
+ peer->as = remote_as;
+ peer->local_id = bgp->router_id;
+ peer->v_holdtime = bgp->default_holdtime;
peer->v_keepalive = bgp->default_keepalive;
if (peer_sort (peer) == BGP_PEER_IBGP)
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- peer = peer_lock (peer); /* bgp peer list reference */
+ SET_FLAG(peer->sflags, PEER_STATUS_REAL_PEER) ;
+ peer = bgp_peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
- /* If "default ipv4-unicast", then this is implicit "activate" */
- active = peer_active (peer);
- if (afi && safi)
+ /* If required, activate given AFI/SAFI -- eg "default ipv4-unicast" */
+ if (enable)
peer->afc[afi][safi] = 1;
/* Last read time set */
@@ -802,70 +797,102 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
/* Make peer's address string. */
peer->host = sockunion_su2str (su, MTYPE_BGP_PEER_HOST) ;
- /* register */
+ /* session -- NB: *before* peer is registered, so before any possible
+ * lookup up by accept() in the BGP Engine
+ */
+ bgp_session_init_new(peer);
+
+ /* register -- NB: *after* peer->session set, so safe */
bgp_peer_index_register(peer, &peer->su);
- /* session */
- peer->session = bgp_session_init_new(peer->session, peer);
+ /* Fire up any timers that should run during pIdle */
+ bgp_peer_timers_set (peer);
- /* If implicit activate, Set up peer's events and timers. */
- if ((! active) && peer_active (peer))
- {
- bgp_timer_set (peer);
- bgp_peer_enable (peer);
- } ;
+ /* If require, enable now all is ready */
+ if (enable)
+ bgp_peer_enable(peer) ;
return peer;
}
-/* Delete peer from configuration.
+/*------------------------------------------------------------------------------
+ * Delete peer from configuration.
*
* The peer is moved to a dead-end "Deleted" neighbour-state, to allow
* it to "cool off" and refcounts to hit 0, at which state it is freed.
*
- * This function /should/ take care to be idempotent, to guard against
- * it being called multiple times through stray events that come in
- * that happen to result in this function being called again. That
- * said, getting here for a "Deleted" peer is a bug in the neighbour
- * FSM.
*/
int
-peer_delete (struct peer *peer)
+bgp_peer_delete (struct peer *peer)
{
int i;
afi_t afi;
safi_t safi;
struct bgp *bgp;
struct bgp_filter *filter;
- struct listnode *pn;
- assert (peer->state != bgp_peer_sDeleted);
+ bgp = peer->bgp ;
- bgp = peer->bgp;
+ /* Once peer is pDeleting it should be impossible to find in order to
+ * bgp_peer_delete() it !
+ */
+ assert (peer->state != bgp_peer_pDeleting);
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
+ /* If the peer is active, then need to shut it down now. If there are any
+ * stale routes, flush them now.
+ *
+ * If the peer ends up in pClearing state, that implies that some background
+ * work is required to completely clear this peer. So increment the
+ * reference count to hold the peer in existence. That will be decremented
+ * again in bgp_peer_clearing_completed().
+ *
+ * If the peer ends up in sIdle state, that implies that any routes that
+ * needed clearing have been dealt with.
+ *
+ * There may be a session in existence. If so, it must either be sLimping or
+ * sDisabled.
+ *
+ * Changing to pDeleting state turns off all timers.
+ */
+ bgp_peer_down(peer, PEER_DOWN_NEIGHBOR_DELETE) ;
- /* If this peer belongs to peer group, clear up the
- relationship. */
- if (peer->group)
- {
- if ((pn = listnode_lookup (peer->group->peer, peer)))
- {
- peer = peer_unlock (peer); /* group->peer list reference */
- list_delete_node (peer->group->peer, pn);
- }
- peer->group = NULL;
- }
+ if (peer->state == bgp_peer_pClearing)
+ bgp_peer_lock (peer) ;
+ else
+ assert(peer->state == bgp_peer_pIdle) ;
+
+ bgp_peer_change_status (peer, bgp_peer_pDeleting);
- /* Withdraw all information from routing table. We can not use
- * BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is
- * executed after peer structure is deleted.
+ /* Increment count of peers lingering in pDeleting
+ *
+ * The count is used while terminating bgpd -- keeps all the nexuses running
+ * until this count drops to zero.
*/
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_peer_stop (peer);
- peer_change_status (peer, bgp_peer_sDeleted);
- bgp_clear_route_all(peer);
+ bm->peer_linger_count++ ;
+
+ /* If is an rsclient in its own right, remove from rsclient list */
+ if (peer_rsclient_active (peer))
+ {
+ struct listnode *pn;
+ pn = listnode_lookup (bgp->rsclient, peer) ;
+
+ bgp_peer_unlock (peer); /* rsclient list reference */
+ list_delete_node (bgp->rsclient, pn);
+ } ;
+
+ /* If this peer belongs to peer group, clear up the relationship. */
+ if (peer->group != NULL)
+ {
+ struct listnode *pn;
+ pn = listnode_lookup (peer->group->peer, peer) ;
+
+ assert(pn != NULL) ;
+
+ bgp_peer_unlock (peer); /* group->peer list reference */
+ list_delete_node (peer->group->peer, pn);
+
+ peer->group = NULL;
+ } ;
/* Password configuration */
if (peer->password)
@@ -874,36 +901,48 @@ peer_delete (struct peer *peer)
peer->password = NULL;
}
- bgp_timer_set (peer); /* stops all timers for Deleted */
-
- /* Delete from all peer list. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && (pn = listnode_lookup (bgp->peer, peer)))
+ /* Delete from bgp->peer list, if required. */
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_REAL_PEER))
{
- peer_unlock (peer); /* bgp peer list reference */
+ struct listnode *pn;
+ pn = listnode_lookup (bgp->peer, peer) ;
+
+ assert(pn != NULL) ;
+
+ bgp_peer_unlock (peer); /* bgp peer list reference */
list_delete_node (bgp->peer, pn);
- }
+ } ;
- if (peer_rsclient_active (peer)
- && (pn = listnode_lookup (bgp->rsclient, peer)))
- {
- peer_unlock (peer); /* rsclient list reference */
- list_delete_node (bgp->rsclient, pn);
+ /* Discard rsclient ribs which are owned by group
+ * and cross-check rib pointer and PEER_FLAG_RSERVER_CLIENT.
+ */
+ 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_RSERVER_CLIENT))
+ {
+ assert(peer->rib[afi][safi] != NULL) ;
+ if (peer->af_group[afi][safi])
+ {
+ peer->rib[afi][safi] = NULL ;
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ;
+ } ;
+ }
+ else
+ assert(peer->rib[afi][safi] == NULL) ;
- /* Clear our own rsclient ribs. */
- 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_RSERVER_CLIENT))
- bgp_clear_route_rsclient(peer, afi, safi);
- }
+ /* Can now clear any rsclient ribs. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (peer->rib[afi][safi] != NULL)
+ {
+ bgp_clear_rsclient_rib(peer, afi, safi) ;
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ;
+ } ;
- /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not
- member of a peer_group. */
+ /* Have now finished with any rsclient ribs */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (peer->rib[afi][safi] && ! peer->af_group[afi][safi])
- bgp_table_finish (&peer->rib[afi][safi]);
+ bgp_table_finish (&peer->rib[afi][safi]) ;
/* Buffers. */
if (peer->ibuf)
@@ -955,27 +994,89 @@ peer_delete (struct peer *peer)
peer->default_rmap[afi][safi].name = NULL;
}
- peer_unlock (peer); /* initial reference */
+ /* Unregister the peer.
+ *
+ * NB: the peer can no longer be looked up by its 'name'.
+ *
+ * In particular this means that the accept() logic in the BGP Engine
+ * will conclude that the session should not be accepting connections.
+ *
+ * NB: also (currently) releases the peer_id -- which may not be so clever ?
+ */
+ if (peer->index_entry != NULL)
+ bgp_peer_index_deregister(peer, &peer->su);
+
+ /* Tear down session, if any and if possible. */
+ bgp_session_delete(peer) ;
+
+ /* Finally: count down the initial reference, which will delete the peer
+ * iff everything else has finished with it.
+ */
+ bgp_peer_unlock (peer); /* initial reference */
return 0;
+} ;
+
+/*------------------------------------------------------------------------------
+ * increase reference count on a struct peer
+ */
+struct peer *
+bgp_peer_lock (struct peer *peer)
+{
+ assert (peer && (peer->lock >= 0));
+
+ peer->lock++;
+
+ return peer;
}
-void
-peer_free (struct peer *peer)
+/*------------------------------------------------------------------------------
+ * decrease reference count on a struct peer
+ *
+ * If is last reference, the structure is freed and NULL returned
+ */
+struct peer *
+bgp_peer_unlock (struct peer *peer)
{
- assert (peer->state == bgp_peer_sDeleted);
+ assert (peer && (peer->lock > 0));
- bgp_unlock(peer->bgp);
+ peer->lock--;
- /* this /ought/ to have been done already through bgp_stop earlier,
- * but just to be sure..
- */
- bgp_timer_set (peer);
- BGP_EVENT_FLUSH (peer);
+ if (peer->lock == 0)
+ {
+#if 0
+ zlog_debug ("unlocked and freeing");
+ zlog_backtrace (LOG_DEBUG);
+#endif
+ bgp_peer_free (peer);
+ return NULL;
+ }
- /* unregister */
- if (peer->index_entry != NULL)
- bgp_peer_index_deregister(peer, &peer->su);
+#if 0
+ if (peer->lock == 1)
+ {
+ zlog_debug ("unlocked to 1");
+ zlog_backtrace (LOG_DEBUG);
+ }
+#endif
+
+ return peer;
+}
+
+/*------------------------------------------------------------------------------
+ * Dismantle and free peer data structure.
+ */
+static void
+bgp_peer_free (struct peer *peer)
+{
+ struct bgp* bgp ;
+
+ assert (peer->state == bgp_peer_pDeleting);
+ assert (peer->session == NULL) ; /* session holds a lock on peer */
+
+ bm->peer_linger_count-- ;
+
+ bgp = peer->bgp ;
if (peer->desc)
XFREE (MTYPE_PEER_DESC, peer->desc);
@@ -991,110 +1092,785 @@ peer_free (struct peer *peer)
if (peer->update_if)
XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- if (peer->clear_node_queue)
- work_queue_free (peer->clear_node_queue);
-
- /* session */
- if (peer->session)
- bgp_session_free(peer->session);
-
bgp_sync_delete (peer);
- memset (peer, 0, sizeof (struct peer));
+ memset (peer, 0, sizeof (struct peer));
+ peer->lock = -54321 ;
XFREE (MTYPE_BGP_PEER, peer);
-}
+ bgp_unlock(bgp);
+} ;
+
+/*------------------------------------------------------------------------------
+ * Enable Peer
+ *
+ * This means that something has changed, and session can be started, if no
+ * session has already started.
+ *
+ * So does nothing unless in pIdle, and expects the session state to be:
+ *
+ * - sIdle, sDisabled or no session at all -- session enabled if possible
+ *
+ * - sEnabled -- session already enabled, so do nothing
+ *
+ * - sEstablished -- IMPOSSIBLE
+ *
+ * - sLimping -- cannot, yet, start a new session -- that will happen in due
+ * course.
+ *
+ * This means that any change which requires the session to be taken down and
+ * restarted needs to call bgp_peer_disable().
+ *
+ * The other peer states:
+ *
+ * - pEstablished == sEstablished
+ *
+ * - pClearing -- cannot restart the peer yet, that will happen in due course.
+ *
+ * - pDeleted -- Enable peer makes no sense... asserts invalid.
+ *
+ * TODO: assert !pEstablished in bgp_peer_enable ?
+ */
void
-peer_nsf_stop (struct peer *peer)
+bgp_peer_enable(bgp_peer peer)
{
- afi_t afi;
- safi_t safi;
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+
+ /* Enable the session unless:
+ * 1) session is active -- ie sEnabled/sLimping (see above)
+ * 2) no address family is activated
+ * 3) the peer has been shutdown
+ * 4) is dealing with prefix overflow (waiting for timer)
+ */
+
+ if (bgp_session_is_active(peer->session))
+ assert(peer->session->state != bgp_session_sEstablished) ;
+ else
+ {
+ if (peer_active (peer)
+ && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
+ && !CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+ {
+ /* enable the session */
+ zlog_err ("%s: enabling peer %s:", __func__, peer->host) ;
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+ bgp_peer_reset_idle(peer) ; /* tidy up */
+ bgp_session_enable(peer);
+ } ;
+ } ;
+ break ;
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
- peer->nsf[afi][safi] = 0;
+ case bgp_peer_pEstablished:
+ break ;
- if (peer->t_gr_restart)
+ case bgp_peer_pClearing:
+ break ;
+
+ case bgp_peer_pDeleting:
+ zabort("cannot enable a pDeleting peer") ;
+ break ;
+
+ default:
+ zabort("unknown peer->state") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Down Peer -- bring down any existing session and restart if possible.
+ *
+ * The following "why_down" values are special:
+ *
+ * - PEER_DOWN_NSF_CLOSE_SESSION
+ *
+ * causes NSF to be turned on as the peer is stopped and routes are cleared.
+ *
+ * - PEER_DOWN_USER_SHUTDOWN
+ *
+ * causes the peer to be shutdown -- so won't restart.
+ *
+ * - PEER_DOWN_NEIGHBOR_DELETE
+ *
+ * prevents the peer from restarting.
+ *
+ * If there is an active session, then it must be disabled, sending the given
+ * notification, or one based on the reason for downing the peer.
+ *
+ * If there is no active session, any stale NSF routes will be cleared.
+ *
+ * So any session ends up as:
+ *
+ * sIdle -- wasn't active and still isn't
+ *
+ * sLimping -- was sEnabled or sEstablished, we now wait for BGP Engine
+ * to complete the disable action and signal when done.
+ *
+ * sDisabled -- has previously been disabled.
+ *
+ * The result depends on the initial peer state:
+ *
+ * 1. bgp_peer_pIdle
+ *
+ * Any session that was sEnabled will have been disabled -- and will now
+ * be sLimping.
+ *
+ * The peer will have automatically restarted, if possible.
+ *
+ * Noting that PEER_DOWN_USER_SHUTDOWN and PEER_DOWN_NEIGHBOR_DELETE both
+ * prevent any restart.
+ *
+ * 2. bgp_peer_pEstablished
+ *
+ * The session will have been disabled -- and will now be sLimping.
+ *
+ * See bgp_peer_stop() for the state of the peer.
+ *
+ * 3. bgp_peer_pClearing
+ *
+ * In this state the session can only be:
+ *
+ * sLimping -- session disable has been sent to the BGP Engine.
+ * sDisabled -- session has been disabled by the BGP Engine
+ *
+ * because peer must have been pEstablished immediately before.
+ *
+ * Do nothing -- will proceed to pIdle in due course.
+ *
+ * 4. bgp_peer_pDeleting
+ *
+ * In this state there may be no session at all, or the session can
+ * only be:
+ *
+ * sIdle -- session never got going
+ * sLimping -- session disable has been sent to the BGP Engine.
+ * sDisabled -- session has been disabled by the BGP Engine
+ *
+ * Do nothing -- peer will be deleted in due course.
+ */
+void
+bgp_peer_down(bgp_peer peer, peer_down_t why_down)
+{
+ bgp_peer_down_notify(peer, why_down, NULL) ;
+} ;
+
+static void
+bgp_peer_down_notify(bgp_peer peer, peer_down_t why_down,
+ bgp_notify notification)
+{
+ /* Deal with session (if any). */
+
+ if (bgp_session_is_active(peer->session))
{
- BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart timer stopped", peer->host);
+ if (notification == NULL)
+ notification = bgp_peer_map_peer_down(why_down) ;
+
+ bgp_notify_set_dup(&peer->session->notification, notification) ;
+
+ bgp_session_disable(peer, notification) ;
}
- if (peer->t_gr_stale)
+ else
+ bgp_notify_free(notification) ; /* Discard unused notification */
+
+ /* Now worry about the state of the peer */
+
+ if (why_down == PEER_DOWN_USER_SHUTDOWN)
+ bgp_peer_shutdown(peer) ;
+
+ if (why_down != PEER_DOWN_NULL)
+ peer->last_reset = why_down ;
+
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+ assert(!bgp_session_is_active(peer->session)
+ || (peer->session->state == bgp_session_sLimping)) ;
+
+ bgp_peer_nsf_stop (peer) ; /* flush stale routes, if any */
+
+ if (why_down != PEER_DOWN_NEIGHBOR_DELETE)
+ bgp_peer_enable(peer) ; /* Restart if possible. */
+
+ break ;
+
+ case bgp_peer_pEstablished:
+ assert(peer->session->state == bgp_session_sLimping) ;
+
+ bgp_peer_stop(peer, why_down == PEER_DOWN_NSF_CLOSE_SESSION) ;
+
+ break ;
+
+ case bgp_peer_pClearing:
+ assert( (peer->session->state == bgp_session_sLimping)
+ || (peer->session->state == bgp_session_sDisabled) ) ;
+
+ bgp_peer_nsf_stop (peer) ; /* flush stale routes, if any */
+
+ break ;
+
+ case bgp_peer_pDeleting:
+ assert( (peer->session == NULL)
+ || (peer->session->state == bgp_session_sIdle)
+ || (peer->session->state == bgp_session_sLimping)
+ || (peer->session->state == bgp_session_sDisabled) ) ;
+ break ;
+
+ default:
+ zabort("unknown peer->state") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Notify the far end that an error has been detected, and close down the
+ * session.
+ *
+ * The session will have been established, so the IdleHoldTime will be extended.
+ *
+ * Because it knows no better, the session will be restarted.
+ */
+extern void
+bgp_peer_down_error(struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode)
+{
+ bgp_peer_down_error_with_data (peer, code, subcode, NULL, 0);
+}
+
+/*------------------------------------------------------------------------------
+ * Notify the far end that an error has been detected, and close down the
+ * session.
+ *
+ * Same as above, except that this accepts a data part for the notification
+ * message.
+ */
+extern void
+bgp_peer_down_error_with_data (struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode,
+ const u_int8_t* data, size_t datalen)
+{
+ bgp_notify notification;
+ notification = bgp_notify_new_with_data(code, subcode, data, datalen);
+
+ bgp_peer_down_notify(peer, bgp_peer_map_notification(notification),
+ notification) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Construct notification based on the reason for bringing down the session
+ *
+ * Where the session is brought down by the other end, returns NULL.
+ */
+static bgp_notify
+bgp_peer_map_peer_down(peer_down_t why_down)
+{
+ bgp_nom_code_t code ;
+ bgp_nom_subcode_t subcode ;
+
+ assert((why_down >= PEER_DOWN_first) && (why_down < PEER_DOWN_count)) ;
+
+ code = BGP_NOMC_CEASE ; /* Default values */
+ subcode = BGP_NOMS_UNSPECIFIC ;
+
+ switch(why_down)
+ {
+ case PEER_DOWN_NULL:
+ return NULL ;
+
+ /* Session taken down at this end for some unspecified reason */
+
+ case PEER_DOWN_UNSPECIFIED:
+ break ;
+
+ /* Configuration changes that cause a session to be reset. */
+
+ case PEER_DOWN_CONFIG_CHANGE:
+ case PEER_DOWN_RID_CHANGE:
+ case PEER_DOWN_REMOTE_AS_CHANGE:
+ case PEER_DOWN_LOCAL_AS_CHANGE:
+ case PEER_DOWN_CLID_CHANGE:
+ case PEER_DOWN_CONFED_ID_CHANGE:
+ case PEER_DOWN_CONFED_PEER_CHANGE:
+ case PEER_DOWN_RR_CLIENT_CHANGE:
+ case PEER_DOWN_RS_CLIENT_CHANGE:
+ case PEER_DOWN_UPDATE_SOURCE_CHANGE:
+ case PEER_DOWN_AF_ACTIVATE:
+ case PEER_DOWN_RMAP_BIND:
+ case PEER_DOWN_RMAP_UNBIND:
+ case PEER_DOWN_CAPABILITY_CHANGE:
+ case PEER_DOWN_PASSIVE_CHANGE:
+ case PEER_DOWN_MULTIHOP_CHANGE:
+ case PEER_DOWN_AF_DEACTIVATE:
+ case PEER_DOWN_PASSWORD_CHANGE:
+ case PEER_DOWN_ALLOWAS_IN_CHANGE:
+ subcode = BGP_NOMS_C_CONFIG ;
+ break ;
+
+ /* Other actions that cause a session to be reset */
+
+ case PEER_DOWN_USER_SHUTDOWN:
+ subcode = BGP_NOMS_C_SHUTDOWN ;
+ break ;
+
+ case PEER_DOWN_USER_RESET:
+ subcode = BGP_NOMS_C_RESET ;
+ break ;
+
+ case PEER_DOWN_NEIGHBOR_DELETE:
+ subcode = BGP_NOMS_C_DECONFIG ;
+ break ;
+
+ case PEER_DOWN_INTERFACE_DOWN:
+ return NULL ; /* nowhere to send a notification ! */
+
+ /* Errors and problems that cause a session to be reset */
+ /* */
+ /* SHOULD really have a notification constructed for these, but for */
+ /* completeness construct an "unspecified" for these. */
+
+ case PEER_DOWN_MAX_PREFIX:
+ subcode = BGP_NOMS_C_MAX_PREF ;
+ break ;
+
+ case PEER_DOWN_HEADER_ERROR:
+ code = BGP_NOMC_HEADER ;
+ break ;
+
+ case PEER_DOWN_OPEN_ERROR:
+ code = BGP_NOMC_OPEN ;
+ break ;
+
+ case PEER_DOWN_UPDATE_ERROR:
+ code = BGP_NOMC_UPDATE ;
+ break ;
+
+ case PEER_DOWN_HOLD_TIMER:
+ code = BGP_NOMC_HOLD_EXP ;
+ break ;
+
+ case PEER_DOWN_FSM_ERROR:
+ code = BGP_NOMC_FSM ;
+ break ;
+
+ case PEER_DOWN_DYN_CAP_ERROR:
+ code = BGP_NOMC_DYN_CAP ;
+ break ;
+
+ /* Things the far end can do to cause a session to be reset */
+
+ case PEER_DOWN_NOTIFY_RECEIVED:
+ return NULL ; /* should not get here ! */
+
+ case PEER_DOWN_CLOSE_SESSION:
+ case PEER_DOWN_NSF_CLOSE_SESSION:
+ return NULL ; /* nowhere to send a notification ! */
+
+ /* To keep the compiler happy. */
+ case PEER_DOWN_count:
+ break ; /* should have asserted already */
+ } ;
+
+ return bgp_notify_new(code, subcode) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Construct reason for bringing down the session based on the notification
+ */
+static peer_down_t
+bgp_peer_map_notification(bgp_notify notification)
+{
+ switch (bgp_notify_get_code(notification)) /* deals with NULL */
+ {
+ case BGP_NOMC_UNDEF:
+ break ;
+
+ case BGP_NOMC_HEADER:
+ return PEER_DOWN_HEADER_ERROR ;
+
+ case BGP_NOMC_OPEN:
+ return PEER_DOWN_OPEN_ERROR ;
+
+ case BGP_NOMC_UPDATE:
+ return PEER_DOWN_UPDATE_ERROR ;
+
+ case BGP_NOMC_HOLD_EXP:
+ return PEER_DOWN_HOLD_TIMER ;
+
+ case BGP_NOMC_FSM:
+ return PEER_DOWN_FSM_ERROR ;
+
+ case BGP_NOMC_CEASE:
+ switch (notification->subcode)
+ {
+ case BGP_NOMS_C_MAX_PREF:
+ return PEER_DOWN_MAX_PREFIX ;
+
+ case BGP_NOMS_C_SHUTDOWN:
+ return PEER_DOWN_USER_SHUTDOWN ;
+
+ case BGP_NOMS_C_DECONFIG:
+ return PEER_DOWN_NEIGHBOR_DELETE ;
+
+ case BGP_NOMS_C_RESET:
+ return PEER_DOWN_USER_RESET ;
+
+ case BGP_NOMS_C_REJECTED: /* should not get here */
+ return PEER_DOWN_NULL ;
+
+ case BGP_NOMS_C_CONFIG:
+ return PEER_DOWN_CONFIG_CHANGE ;
+
+ case BGP_NOMS_C_COLLISION: /* should not get here */
+ return PEER_DOWN_NULL ;
+
+ case BGP_NOMS_C_RESOURCES: /* not used */
+ return PEER_DOWN_NULL ;
+
+ default:
+ break ;
+ } ;
+ break ;
+
+ case BGP_NOMC_DYN_CAP:
+ return PEER_DOWN_DYN_CAP_ERROR ;
+
+ default:
+ break ;
+ } ;
+
+ return PEER_DOWN_UNSPECIFIED ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Background route clearing has completed.
+ *
+ * If there is any background work required to clear routes for a given peer,
+ * then when that completes, this is called to move the state of the peer
+ * forwards.
+ */
+extern void
+bgp_peer_clearing_completed(struct peer *peer)
+{
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+ case bgp_peer_pEstablished:
+ zabort("invalid peer->state") ;
+ break ;
+
+ case bgp_peer_pClearing:
+ bgp_peer_change_status (peer, bgp_peer_pIdle);
+ bgp_peer_enable(peer);
+ break ;
+
+ case bgp_peer_pDeleting:
+ bgp_peer_unlock (peer); /* route clearing "reference" */
+ break ;
+
+ default:
+ zabort("unknown peer->state") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set new peer state.
+ *
+ * If state changes, do dump new state and log state change if required.
+ *
+ * In any case, set timers for the new state -- so if state hasn't changed,
+ * will restart those timers.
+ */
+static void
+bgp_peer_change_status (bgp_peer peer, bgp_peer_state_t new_state)
+{
+ if (peer->state != new_state)
{
+ bgp_dump_state (peer, peer->state, new_state);
+
+ /* Preserve old status and change into new status. */
+ peer->ostate = peer->state ;
+ peer->state = new_state ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s went from %s to %s", peer->host,
+ LOOKUP (bgp_peer_status_msg, peer->ostate),
+ LOOKUP (bgp_peer_status_msg, peer->state)) ;
+
+ if (new_state == bgp_peer_pIdle)
+ bgp_peer_reset_idle(peer) ; /* tidy up */
+ } ;
+
+ bgp_peer_timers_set (peer);
+} ;
+
+/*==============================================================================
+ * Timer handling
+ */
+
+static void
+bgp_peer_timers_set (struct peer *peer)
+{
+ switch (peer->state)
+ {
+ case bgp_peer_pIdle:
+ /* On entry to pIdle the Graceful Restart Timers are left running:
+ *
+ * - if no connection is established within the Graceful Restart time,
+ * then things are no longer graceful, and the stale routes have to
+ * be thrown away.
+ *
+ * - if routes do not thereafter arrive quickly enough, then the
+ * Graceful Stale time kicks in and stale routes will be thrown away.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv) ;
+ BGP_TIMER_OFF (peer->t_pmax_restart) ;
+ break;
+
+ case bgp_peer_pEstablished:
+ /* On entry to pEstablished only the the Graceful Stale Timer is left
+ * running.
+ *
+ * Any Graceful Restart Timer can be cancelled -- have established in
+ * time.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv) ;
+ BGP_TIMER_OFF (peer->t_pmax_restart) ;
+
+ bgp_graceful_restart_timer_cancel(peer) ;
+ break;
+
+ case bgp_peer_pClearing:
+ /* On entry to pClearing, turn off all timers.
+ *
+ * The Graceful Restart timer should not be running in any case.
+ *
+ * If the session is brought down quickly enough, the Graceful Stale
+ * timer may be running.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv);
+ BGP_TIMER_OFF (peer->t_pmax_restart);
+ BGP_TIMER_OFF (peer->t_gr_restart);
+
+ bgp_graceful_stale_timer_cancel(peer) ;
+ break ;
+
+ case bgp_peer_pDeleting:
+ /* On entry to pDeleting, turn off all timers.
+ */
+ BGP_TIMER_OFF (peer->t_routeadv);
+ BGP_TIMER_OFF (peer->t_pmax_restart);
+ BGP_TIMER_OFF (peer->t_gr_restart);
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
- bgp_clear_route_all (peer);
-}
+ break;
-/* enable the peer */
-void
-bgp_peer_enable(bgp_peer peer)
+ default:
+ assert(0);
+ } ;
+} ;
+
+static int
+bgp_routeadv_timer (struct thread *thread)
{
- /* Don't enable the session if:
- * 1) the peer not idle, which means not ready yet: clearing, deleting or
- * waiting for disable.
- * 2) no address family is activated
- * 3) the peer has been shutdown
- * 4) is dealing with prefix overflow: its timer will enable peer when ready
+ struct peer *peer;
+ uint32_t jittered ;
+ uint32_t jitter ;
+
+ peer = THREAD_ARG (thread);
+ peer->t_routeadv = NULL;
+
+ if (BGP_DEBUG (fsm, FSM))
+ zlog (peer->log, LOG_DEBUG,
+ "%s [FSM] Timer (routeadv timer expire)",
+ peer->host);
+
+ peer->synctime = time (NULL);
+
+ bgp_write(peer, NULL);
+
+ /* Apply +/- 10% jitter to the route advertise timer.
+ *
+ * The time is in seconds, so for anything less than 10 seconds this forced
+ * to be +/- 1 second.
*/
+ jittered = jitter = peer->v_routeadv ;
+ if (jitter < 10)
+ jitter = 10 ;
+ jittered = (jittered * 90) + (rand() % (jitter * 20)) ; /* jitter is +/-10% */
+ jittered = (jittered + 50) / 100 ;
- if ((peer->state == bgp_peer_sIdle)
- && peer_active (peer)
- && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
- && !CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
- {
- /* enable the session */
- zlog_err ("%s: enabling peer %s:", __func__, peer->host) ;
+ /* TODO: move this to the Routeing Engine qtimer pile. */
+ BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, jittered) ;
- bgp_session_enable(peer);
- }
+ return 0;
+}
+
+/* Reset bgp update timer */
+static void
+bgp_uptime_reset (struct peer *peer)
+{
+ peer->uptime = time (NULL);
}
-/* disable the peer
- * sent notification, disable session
+/*------------------------------------------------------------------------------
+ * BGP Peer Down Causes mapped to strings
*/
-void
-bgp_peer_disable(bgp_peer peer, bgp_notify notification)
+const char *peer_down_str[] =
{
- if (bgp_session_is_active(peer->session))
- {
- /* This code has been moved from where it was, in bgp_write */
- /* TODO: not clear whether v_start handling is still correct */
- peer->v_start *= 2;
- if (peer->v_start >= (60 * 2))
- peer->v_start = (60 * 2);
+ [PEER_DOWN_NULL] = "",
+
+ [PEER_DOWN_UNSPECIFIED] = "Unspecified reason",
+
+ [PEER_DOWN_CONFIG_CHANGE] = "Unspecified config change",
+
+ [PEER_DOWN_RID_CHANGE] = "Router ID changed",
+ [PEER_DOWN_REMOTE_AS_CHANGE] = "Remote AS changed",
+ [PEER_DOWN_LOCAL_AS_CHANGE] = "Local AS change",
+ [PEER_DOWN_CLID_CHANGE] = "Cluster ID changed",
+ [PEER_DOWN_CONFED_ID_CHANGE] = "Confederation identifier changed",
+ [PEER_DOWN_CONFED_PEER_CHANGE] = "Confederation peer changed",
+ [PEER_DOWN_RR_CLIENT_CHANGE] = "RR client config change",
+ [PEER_DOWN_RS_CLIENT_CHANGE] = "RS client config change",
+ [PEER_DOWN_UPDATE_SOURCE_CHANGE] = "Update source change",
+ [PEER_DOWN_AF_ACTIVATE] = "Address family activated",
+ [PEER_DOWN_RMAP_BIND] = "Peer-group add member",
+ [PEER_DOWN_RMAP_UNBIND] = "Peer-group delete member",
+ [PEER_DOWN_CAPABILITY_CHANGE] = "Capability changed",
+ [PEER_DOWN_PASSIVE_CHANGE] = "Passive config change",
+ [PEER_DOWN_MULTIHOP_CHANGE] = "Multihop config change",
+ [PEER_DOWN_AF_DEACTIVATE] = "Address family deactivated",
+ [PEER_DOWN_PASSWORD_CHANGE] = "MD5 Password changed",
+ [PEER_DOWN_ALLOWAS_IN_CHANGE] = "Allow AS in changed",
+
+ [PEER_DOWN_USER_SHUTDOWN] = "Admin. shutdown",
+ [PEER_DOWN_USER_RESET] = "User reset",
+ [PEER_DOWN_NEIGHBOR_DELETE] = "Neighbor deleted",
+
+ [PEER_DOWN_INTERFACE_DOWN] = "Interface down",
+
+ [PEER_DOWN_MAX_PREFIX] = "Max Prefix Limit exceeded",
+
+ [PEER_DOWN_HEADER_ERROR] = "Error in message header",
+ [PEER_DOWN_OPEN_ERROR] = "Error in BGP OPEN message",
+ [PEER_DOWN_UPDATE_ERROR] = "Error in BGP UPDATE message",
+ [PEER_DOWN_HOLD_TIMER] = "HoldTimer expired",
+ [PEER_DOWN_FSM_ERROR] = "Error in FSM sequence",
+ [PEER_DOWN_DYN_CAP_ERROR] = "Error in Dynamic Capability",
+
+ [PEER_DOWN_NOTIFY_RECEIVED] = "Notification received",
+ [PEER_DOWN_NSF_CLOSE_SESSION] = "NSF peer closed the session",
+ [PEER_DOWN_CLOSE_SESSION] = "Peer closed the session",
+} ;
+
+CONFIRM(sizeof(peer_down_str) == (PEER_DOWN_count * sizeof(const char*))) ;
- bgp_session_disable(peer, notification);
+/*------------------------------------------------------------------------------
+ * Graceful Restart timer has expired.
+ *
+ * MUST be pIdle or pClearing -- transition to pEstablished cancels this timer.
+ *
+ * Clears out stale routes and stops the Graceful Restart Stale timer.
+ *
+ * Clears down PEER_STATUS_NSF_MODE & PEER_STATUS_NSF_WAIT.
+ */
+static int
+bgp_graceful_restart_timer_expire (struct thread *thread)
+{
+ struct peer *peer;
+
+ peer = THREAD_ARG (thread);
+ peer->t_gr_restart = NULL;
+
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart timer expired", peer->host) ;
+
+ bgp_peer_nsf_stop (peer) ;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ * Cancel any Graceful Restart timer
+ *
+ * NB: does NOT do anything about any stale routes or about any stale timer !
+ */
+static void
+bgp_graceful_restart_timer_cancel (struct peer* peer)
+{
+ if (peer->t_gr_restart)
+ {
+ BGP_TIMER_OFF (peer->t_gr_restart);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart timer stopped", peer->host);
}
+} ;
+
+/*------------------------------------------------------------------------------
+ * Graceful Restart Stale timer has expired.
+ *
+ * SHOULD be pEstablished, because otherwise the Graceful Restart timer should
+ * have gone off before this does, and cancelled this.
+ *
+ * To be safe, if not pEstablished, then MUST be pIdle or pClearing, so can do
+ * bgp_peer_nsf_stop (peer).
+ *
+ * Clears out stale routes and stops the Graceful Restart Stale timer.
+ *
+ * Clears down PEER_STATUS_NSF_MODE & PEER_STATUS_NSF_WAIT.
+ */
+static int
+bgp_graceful_stale_timer_expire (struct thread *thread)
+{
+ struct peer *peer;
+
+ peer = THREAD_ARG (thread);
+ peer->t_gr_stale = NULL;
+
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
+
+ if (peer->state == bgp_peer_pEstablished)
+ bgp_peer_clear_all_stale_routes(peer) ;
else
+ bgp_peer_nsf_stop(peer) ;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ * Cancel any Graceful Restart Stale timer
+ *
+ * NB: does NOT do anything about any stale routes !
+ */
+static void
+bgp_graceful_stale_timer_cancel (struct peer* peer)
+{
+ if (peer->t_gr_stale)
{
- bgp_notify_free(notification) ;
- bgp_peer_stop(peer);
+ BGP_TIMER_OFF (peer->t_gr_stale);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
}
-}
+} ;
-/* Called after event occurred, this function changes status */
-void
-peer_change_status (bgp_peer peer, int status)
+#if 0
+/* BGP peer is stopped by the error. */
+static int
+bgp_stop_with_error (struct peer *peer)
{
- bgp_dump_state (peer, peer->state, status);
+ /* Double start timer. */
+ peer->v_start *= 2;
- /* Preserve old status and change into new status. */
- peer->ostate = peer->state;
- peer->state = status;
+ /* Overflow check. */
+ if (peer->v_start >= (60 * 2))
+ peer->v_start = (60 * 2);
+
+ bgp_stop (peer);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s went from %s to %s",
- peer->host,
- LOOKUP (bgp_peer_status_msg, peer->ostate),
- LOOKUP (bgp_peer_status_msg, peer->state));
+ return 0;
}
+#endif
+
/*==============================================================================
* For the given interface name, get a suitable address so can bind() before
diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h
index 91070377..ab32117c 100644
--- a/bgpd/bgp_peer.h
+++ b/bgpd/bgp_peer.h
@@ -106,6 +106,72 @@ struct bgp_filter
*
*/
+enum PEER_DOWN {
+ PEER_DOWN_first = 0,
+
+ PEER_DOWN_NULL = 0, /* Not a PEER_DOWN */
+
+ /* Session taken down at this end for some unspecified reason */
+
+ PEER_DOWN_UNSPECIFIED,
+
+ /* Configuration changes that cause a session to be reset. */
+
+ PEER_DOWN_CONFIG_CHANGE, /* Unspecified config change */
+
+ PEER_DOWN_RID_CHANGE, /* 'bgp router-id' */
+ PEER_DOWN_REMOTE_AS_CHANGE, /* 'neighbor remote-as' */
+ PEER_DOWN_LOCAL_AS_CHANGE, /* 'neighbor local-as' */
+ PEER_DOWN_CLID_CHANGE, /* 'bgp cluster-id' */
+ PEER_DOWN_CONFED_ID_CHANGE, /* 'bgp confederation identifier' */
+ PEER_DOWN_CONFED_PEER_CHANGE, /* 'bgp confederation peer' */
+ PEER_DOWN_RR_CLIENT_CHANGE, /* 'neighbor route-reflector-client' */
+ PEER_DOWN_RS_CLIENT_CHANGE, /* 'neighbor route-server-client' */
+ PEER_DOWN_UPDATE_SOURCE_CHANGE, /* 'neighbor update-source' */
+ PEER_DOWN_AF_ACTIVATE, /* 'neighbor activate' */
+ PEER_DOWN_RMAP_BIND, /* 'neighbor peer-group' */
+ PEER_DOWN_RMAP_UNBIND, /* 'no neighbor peer-group' */
+ PEER_DOWN_CAPABILITY_CHANGE, /* 'neighbor capability' */
+ PEER_DOWN_PASSIVE_CHANGE, /* 'neighbor passive' */
+ PEER_DOWN_MULTIHOP_CHANGE, /* 'neighbor multihop' */
+ PEER_DOWN_AF_DEACTIVATE, /* 'no neighbor activate' */
+ PEER_DOWN_PASSWORD_CHANGE, /* password changed */
+ PEER_DOWN_ALLOWAS_IN_CHANGE, /* allowas-in change */
+
+ /* Other actions that cause a session to be reset */
+
+ PEER_DOWN_USER_SHUTDOWN, /* 'neighbor shutdown' */
+ PEER_DOWN_USER_RESET, /* 'clear ip bgp' */
+ PEER_DOWN_NEIGHBOR_DELETE, /* neighbor delete */
+
+ PEER_DOWN_INTERFACE_DOWN, /* interface reported to be down */
+
+ /* Errors and problems that cause a session to be reset */
+
+ PEER_DOWN_MAX_PREFIX, /* max prefix limit exceeded */
+
+ PEER_DOWN_HEADER_ERROR, /* error in BGP Message header */
+ PEER_DOWN_OPEN_ERROR, /* error in BGP OPEN message */
+ PEER_DOWN_UPDATE_ERROR, /* error in BGP UPDATE message */
+ PEER_DOWN_HOLD_TIMER, /* HoldTimer expired */
+ PEER_DOWN_FSM_ERROR, /* error in FSM sequence */
+ PEER_DOWN_DYN_CAP_ERROR, /* error in Dynamic Capability */
+
+ /* Things the far end can do to cause a session to be reset */
+
+ PEER_DOWN_NOTIFY_RECEIVED, /* notification received */
+ PEER_DOWN_CLOSE_SESSION, /* tcp session close */
+ PEER_DOWN_NSF_CLOSE_SESSION, /* NSF tcp session close */
+
+ /* Number of down causes */
+ PEER_DOWN_count
+} ;
+
+typedef enum PEER_DOWN peer_down_t ;
+
+
+
+
struct peer
{
/* BGP structure. */
@@ -156,35 +222,35 @@ struct peer
struct stream *work;
/* Status of the peer. */
- bgp_peer_state_t state; /* current state */
- bgp_peer_state_t ostate; /* old state */
+ bgp_peer_state_t state; /* current state */
+ bgp_peer_state_t ostate; /* old state */
/* Peer index, used for dumping TABLE_DUMP_V2 format */
uint16_t table_dump_index;
/* Peer information */
+ bgp_peer_index_entry index_entry ;
bgp_session session ; /* Current session */
- bgp_peer_index_entry index_entry ; /* and our index entry */
-
- int ttl; /* TTL of TCP connection to the peer. */
- char *desc; /* Description of the peer. */
- unsigned short port; /* Destination port for peer */
- char *host; /* Printable address of the peer. */
- union sockunion su; /* Sockunion address of the peer. */
- time_t uptime; /* Last Up/Down time */
- time_t readtime; /* Last read time */
- time_t resettime; /* Last reset time */
-
- unsigned int ifindex; /* ifindex of the BGP connection. */
- char *ifname; /* bind interface name. */
+
+ int ttl; /* TTL of TCP connection to the peer. */
+ char *desc; /* Description of the peer. */
+ unsigned short port; /* Destination port for peer */
+ char *host; /* Printable address of the peer. */
+ union sockunion su; /* Sockunion address of the peer. */
+ time_t uptime; /* Last Up/Down time */
+ time_t readtime; /* Last read time */
+ time_t resettime; /* Last reset time */
+
+ unsigned int ifindex; /* ifindex of the BGP connection. */
+ char *ifname; /* bind interface name. */
char *update_if;
union sockunion *update_source;
struct zlog *log;
- union sockunion *su_local; /* Sockunion of local address. */
- union sockunion *su_remote; /* Sockunion of remote address. */
- int shared_network; /* Is this peer shared same network. */
- struct bgp_nexthop nexthop; /* Nexthop */
+ union sockunion *su_local; /* Sockunion of local address. */
+ union sockunion *su_remote; /* Sockunion of remote address. */
+ int shared_network; /* Is this peer shared same network. */
+ struct bgp_nexthop nexthop; /* Nexthop */
/* Peer address family configuration. */
u_char afc[AFI_MAX][SAFI_MAX];
@@ -265,13 +331,13 @@ struct peer
/* Peer status flags. */
u_int16_t sflags;
-#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_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 */
+#define PEER_STATUS_REAL_PEER (1 << 0) /* not group conf or peer_self */
+#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_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 */
/* Peer status af flags (reset in bgp_stop) */
u_int16_t af_sflags[AFI_MAX][SAFI_MAX];
@@ -285,17 +351,17 @@ struct peer
/* Default attribute value for the peer. */
u_int32_t config;
-#define PEER_CONFIG_WEIGHT (1 << 0) /* Default weight. */
-#define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */
-#define PEER_CONFIG_CONNECT (1 << 2) /* connect */
-#define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */
+#define PEER_CONFIG_WEIGHT (1 << 0) /* Default weight. */
+#define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */
+#define PEER_CONFIG_CONNECT (1 << 2) /* connect */
+#define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */
u_int32_t weight;
u_int32_t holdtime;
u_int32_t keepalive;
u_int32_t connect;
u_int32_t routeadv;
- /* Timer values. */
+ /* Timer values. */
u_int32_t v_start;
u_int32_t v_connect;
u_int32_t v_holdtime;
@@ -305,74 +371,51 @@ struct peer
u_int32_t v_pmax_restart;
u_int32_t v_gr_restart;
- /* Threads. */
+ /* Threads. */
struct thread *t_asorig;
struct thread *t_routeadv;
struct thread *t_pmax_restart;
struct thread *t_gr_restart;
struct thread *t_gr_stale;
- /* workqueues */
- struct work_queue *clear_node_queue;
-
- /* BGP state count */
- u_int32_t established; /* Established */
- u_int32_t dropped; /* Dropped */
+ /* BGP state count */
+ u_int32_t established;
+ u_int32_t dropped;
- /* Synchronization list and time. */
+ /* Synchronization list and time. */
struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX];
time_t synctime;
- /* Send prefix count. */
+ /* Send prefix count. */
unsigned long scount[AFI_MAX][SAFI_MAX];
- /* Announcement attribute hash. */
+ /* Announcement attribute hash. */
struct hash *hash[AFI_MAX][SAFI_MAX];
- /* Filter structure. */
+ /* Filter structure. */
struct bgp_filter filter[AFI_MAX][SAFI_MAX];
- /* ORF Prefix-list */
+ /* ORF Prefix-list */
struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
- /* Prefix count. */
+ /* Prefix count. */
unsigned long pcount[AFI_MAX][SAFI_MAX];
- /* Max prefix count. */
+ /* Max prefix count. */
unsigned long pmax[AFI_MAX][SAFI_MAX];
u_char pmax_threshold[AFI_MAX][SAFI_MAX];
u_int16_t pmax_restart[AFI_MAX][SAFI_MAX];
#define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75
- /* allowas-in. */
+ /* allowas-in. */
char allowas_in[AFI_MAX][SAFI_MAX];
- /* peer reset cause */
- char last_reset;
-#define PEER_DOWN_RID_CHANGE 1 /* bgp router-id command */
-#define PEER_DOWN_REMOTE_AS_CHANGE 2 /* neighbor remote-as command */
-#define PEER_DOWN_LOCAL_AS_CHANGE 3 /* neighbor local-as command */
-#define PEER_DOWN_CLID_CHANGE 4 /* bgp cluster-id command */
-#define PEER_DOWN_CONFED_ID_CHANGE 5 /* bgp confederation identifier command */
-#define PEER_DOWN_CONFED_PEER_CHANGE 6 /* bgp confederation peer command */
-#define PEER_DOWN_RR_CLIENT_CHANGE 7 /* neighbor route-reflector-client command */
-#define PEER_DOWN_RS_CLIENT_CHANGE 8 /* neighbor route-server-client command */
-#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9 /* neighbor update-source command */
-#define PEER_DOWN_AF_ACTIVATE 10 /* neighbor activate command */
-#define PEER_DOWN_USER_SHUTDOWN 11 /* neighbor shutdown command */
-#define PEER_DOWN_USER_RESET 12 /* clear ip bgp command */
-#define PEER_DOWN_NOTIFY_RECEIVED 13 /* notification received */
-#define PEER_DOWN_NOTIFY_SEND 14 /* notification send */
-#define PEER_DOWN_CLOSE_SESSION 15 /* tcp session close */
-#define PEER_DOWN_NEIGHBOR_DELETE 16 /* neghbor delete */
-#define PEER_DOWN_RMAP_BIND 17 /* neghbor peer-group command */
-#define PEER_DOWN_RMAP_UNBIND 18 /* no neighbor peer-group command */
-#define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */
-#define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */
-#define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */
-#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */
-
- /* The kind of route-map Flags.*/
+ /* peer reset cause */
+ peer_down_t last_reset;
+
+ bgp_notify notification ;
+
+ /* The kind of route-map Flags. */
u_char rmap_type;
#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */
#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */
@@ -387,7 +430,7 @@ struct peer
#define BGP_TIMER_ON(T,F,V) \
do { \
- if (!(T) && (peer->state != bgp_peer_sDeleted)) \
+ if (!(T) && (peer->state != bgp_peer_pDeleting)) \
THREAD_TIMER_ON(master,(T),(F),peer,(V)); \
} while (0)
@@ -399,7 +442,7 @@ struct peer
#define BGP_EVENT_ADD(P,E) \
do { \
- if ((P)->state != bgp_peer_sDeleted) \
+ if ((P)->state != bgp_peer_pDeleting) \
thread_add_event (master, bgp_event, (P), (E)); \
} while (0)
@@ -426,39 +469,38 @@ extern const char *peer_down_str[];
extern void
bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag);
-void
-bgp_peer_reenable(bgp_peer peer, bgp_notify notification);
-
extern void
bgp_peer_enable(bgp_peer peer);
extern void
-bgp_peer_disable(bgp_peer peer, bgp_notify notification);
-
-extern int
-bgp_peer_stop (struct peer *peer) ;
+bgp_peer_down(bgp_peer peer, peer_down_t why_down) ;
extern void
-bgp_peer_clearing_completed(struct peer *peer) ;
+bgp_peer_down_error(struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode) ;
+extern void
+bgp_peer_down_error_with_data (struct peer* peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode,
+ const u_int8_t* data, size_t datalen) ;
extern void
-peer_change_status (bgp_peer peer, int status);
+bgp_peer_clearing_completed(struct peer *peer) ;
extern struct peer *
-peer_new (struct bgp *bgp);
+bgp_peer_new (struct bgp *bgp);
extern struct peer *
-peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
- as_t remote_as, afi_t afi, safi_t safi);
+bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
+ as_t remote_as, afi_t afi, safi_t safi);
-extern int
-peer_delete (struct peer *peer);
+extern struct
+peer *bgp_peer_lock (struct peer *) ;
-extern void
-peer_free (struct peer *peer);
+extern struct
+peer *bgp_peer_unlock (struct peer *) ;
-extern void
-peer_nsf_stop (struct peer *peer);
+extern int
+bgp_peer_delete (struct peer *peer);
extern sockunion
bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf) ;
diff --git a/bgpd/bgp_peer_index.c b/bgpd/bgp_peer_index.c
index 5bb7f3d0..518a22bc 100644
--- a/bgpd/bgp_peer_index.c
+++ b/bgpd/bgp_peer_index.c
@@ -24,6 +24,7 @@
#include "bgpd/bgp_peer_index.h"
#include "bgpd/bgp_peer.h"
#include "bgpd/bgp_session.h"
+#include "bgpd/bgp_connection.h"
#include "lib/symtab.h"
#include "lib/vector.h"
@@ -35,17 +36,26 @@
* BGP Peer Index
*
* When peers are created, they are registered in the bgp_peer_index. When
- * they are destroyed, they are removed. This is done by the Routeing Engine.
+ * they are destroyed, they are removed. This is done by the Routing Engine.
*
- * The peer index is used by the Routeing Engine to lookup peers either by
+ * The Peer Index is used by the Routing Engine to lookup peers either by
* name (IP address) or by peer_id.
*
* The BGP Engine needs to lookup sessions when a listening socket accepts a
* connection -- first, to decide whether to continue with the connection, and
- * second, to tie the connection to the right session. It uses the peer index
+ * second, to tie the connection to the right session. It uses the Peer Index
* to do this.
*
- * A mutex is used to coordinate access to the index.
+ * A mutex is used to coordinate access to the index. Only the Routing engine
+ * makes changes to the Peer Index, so it only needs to lock the mutex when it
+ * does make changes. The BGP Engine needs to lock the Peer Index whenever it
+ * accesses it.
+ *
+ * The BGP Engine needs the session associated with a given address if and only
+ * if the session is enabled for accept(), which implies that it is active and
+ * in the hands of the BGP Engine. To get to the session it needs to step
+ * via the peer->session pointer, having found the peer via the index. So,
+ * setting the peer->session pointer is done under the Peer Index Mutex.
*/
static struct symbol_table bgp_peer_index ; /* lookup by 'name' */
@@ -140,7 +150,7 @@ bgp_peer_index_reset(void)
/* Ream out the peer id vector -- checking that all entries are empty */
while ((entry = vector_ream_keep(&bgp_peer_id_index)) != NULL)
- passert(entry->peer == NULL) ;
+ passert((entry->peer == NULL) && (entry->next_free != entry)) ;
/* Discard body of symbol table -- must be empty ! */
symbol_table_reset_keep(&bgp_peer_index) ;
@@ -192,13 +202,14 @@ bgp_peer_index_register(bgp_peer peer, union sockunion* su)
bgp_peer_id_table_make_ids() ;
entry = bgp_peer_id_free_head ;
- bgp_peer_id_free_head = (void*)entry->accept ;
+ bgp_peer_id_free_head = entry->next_free ;
assert(vector_get_item(&bgp_peer_id_index, entry->id) == entry) ;
/* Initialise the entry -- the id is already set */
entry->peer = peer ;
- entry->accept = NULL ;
+ entry->next_free = entry ;
+
peer->index_entry = entry;
/* Insert the new entry into the symbol table. */
@@ -235,7 +246,9 @@ bgp_peer_index_deregister(bgp_peer peer, union sockunion* su)
entry = symbol_delete(sym) ;
- passert((entry != NULL) && (entry->peer == peer) && (entry->accept == NULL)) ;
+ passert( (entry != NULL) && (entry->id != bgp_peer_id_null)
+ && (entry->peer == peer)
+ && (entry->next_free == entry) ) ;
bgp_peer_id_table_free_entry(entry) ;
@@ -271,21 +284,47 @@ bgp_peer_index_seek(union sockunion* su)
extern bgp_peer_index_entry
bgp_peer_index_seek_entry(union sockunion* su)
{
+ bgp_peer_index_entry entry ;
+
/* Only the Routing Engine can add/delete entries -- so no lock required */
- return symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
+ entry = symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
+
+ if (entry != NULL)
+ assert((entry->peer != NULL) && (entry->next_free = entry)) ;
+
+ return entry ;
} ;
/*------------------------------------------------------------------------------
- * Lookup a peer by its address.
+ * Set peer->session field.
*
- * Return a pointer to its session iff it is prepared to accept() a connection.
+ * This is done under the Peer Index Mutex, so that the BGP Engine can step
+ * from the Peer Index entry, via the peer structure, to the session, which is
+ * also controlled by that Mutex, in safety.
+ */
+extern void
+bgp_peer_index_set_session(bgp_peer peer, bgp_session session)
+{
+ BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ peer->session = session ;
+
+ BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+} ;
+
+/*------------------------------------------------------------------------------
+ * Find whether given address is for a known peer, and if so whether it has
+ * an active session which is prepared to accept() a connection.
*
* For use by the BGP Engine.
*
* Returns: bgp_connection if: peer with given address is configured
* and: the session is prepared to accept()
*
+ * Note that the session cannot be deleted while it is in a prepared
+ * to accept state.
+ *
* or: NULL otherwise
*
* Sets *p_found <=> a peer with the given address is configured.
@@ -294,17 +333,25 @@ bgp_peer_index_seek_entry(union sockunion* su)
* is initialised NULL when the index entry is created.
*/
extern bgp_connection
-bgp_peer_index_seek_accept(union sockunion* su, int* p_found)
+bgp_peer_index_seek_accept(union sockunion* su, bool* p_found)
{
- bgp_connection accept ;
+ bgp_connection accept ;
bgp_peer_index_entry entry ;
BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
entry = symbol_get_value(symbol_seek(&bgp_peer_index, su)) ;
- *p_found = (entry != NULL) ;
- accept = *p_found ? entry->accept : NULL ;
+ if (entry != NULL)
+ {
+ *p_found = true ;
+ accept = bgp_connection_query_accept(entry->peer->session) ;
+ }
+ else
+ {
+ *p_found = false ;
+ accept = NULL ;
+ } ;
BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
@@ -333,10 +380,10 @@ bgp_peer_id_table_free_entry(bgp_peer_index_entry entry)
if (bgp_peer_id_free_head == NULL)
bgp_peer_id_free_head = entry ;
else
- bgp_peer_id_free_tail->accept = (void*)entry ;
+ bgp_peer_id_free_tail->next_free = entry ;
bgp_peer_id_free_tail = entry ;
- entry->accept = NULL ; /* used as 'next' for free list */
+ entry->next_free = NULL ;
entry->peer = NULL ; /* only when free ! */
} ;
@@ -363,9 +410,9 @@ bgp_peer_id_table_make_ids(void)
{
confirm(bgp_peer_id_null == 0) ;
- entry->id = 0 ; /* should never be used */
- entry->peer = NULL ; /* invalid in use */
- entry->accept = (void*)entry ; /* invalid if not active ! */
+ entry->id = 0 ; /* should never be used */
+ entry->peer = NULL ; /* invalid in use */
+ entry->next_free = NULL ; /* invalid in use */
++entry ; /* step past id == 0 */
id_new = 1 ; /* avoid setting id == 0 free */
diff --git a/bgpd/bgp_peer_index.h b/bgpd/bgp_peer_index.h
index c99ec710..2ce3fb16 100644
--- a/bgpd/bgp_peer_index.h
+++ b/bgpd/bgp_peer_index.h
@@ -40,20 +40,10 @@ typedef unsigned bgp_peer_id_t ;
struct bgp_peer_index_entry
{
- bgp_peer peer ; /* used by Routing Engine */
+ bgp_peer_index_entry next_free ; /* for list of free peer_id's */
+ /* points to self if entry is in use */
- /* The accept pointer is used by the listening socket(s) to find the
- * session when it is prepared to accept a connection.
- *
- * This pointer MUST be NULL when not sEnabled or sEstablished. It
- * will be set by the BGP Engine when it decides to accept connections,
- * and cleared by it otherwise (and when a session stops).
- *
- * An active session contains a pointer to the peer index entry to
- * facilitate this.
- */
-
- bgp_connection accept ; /* used by BGP Engine */
+ bgp_peer peer ; /* NULL if entry is not in use */
bgp_peer_id_t id ; /* maps IP address to peer_id */
} ;
@@ -88,8 +78,11 @@ bgp_peer_index_seek(sockunion su) ;
extern bgp_peer_index_entry
bgp_peer_index_seek_entry(sockunion su) ;
+extern void
+bgp_peer_index_set_session(bgp_peer peer, bgp_session session) ;
+
extern bgp_connection
-bgp_peer_index_seek_accept(sockunion su, int* p_found) ;
+bgp_peer_index_seek_accept(sockunion su, bool* p_found) ;
#endif /* _QUAGGA_BGP_PEER_INDEX_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index ff7dada3..ca8bee8c 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -205,7 +205,7 @@ bgp_info_add (struct bgp_node *rn, struct bgp_info *ri)
bgp_info_lock (ri);
bgp_lock_node (rn);
- peer_lock (peer); /* bgp_info peer reference */
+ bgp_peer_lock (peer); /* bgp_info peer reference */
}
/* Do the actual removal of info from RIB, for use by bgp_process
@@ -237,7 +237,7 @@ bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri)
bgp_info_unlock (ri); /* fewer references to bgp_info */
bgp_unlock_node (rn); /* fewer references to bgp_node */
- peer_unlock (peer); /* fewer references to peer */
+ bgp_peer_unlock (peer); /* fewer references to peer */
}
void
@@ -1434,7 +1434,7 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
p = &rn->p;
/* Announce route to Established peer. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
/* Address family configuration check. */
@@ -1493,6 +1493,7 @@ bgp_process_rsclient (struct work_queue *wq, work_queue_item item)
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
+ struct bgp_table *table ;
struct peer *rsclient ;
assert(wq->spec.data == item) ;
@@ -1503,12 +1504,20 @@ bgp_process_rsclient (struct work_queue *wq, work_queue_item item)
return WQ_SUCCESS ;
/* hack off queue and prepare to process */
- pq->head = rn->wq_next ;
- rn->on_wq = 0 ;
- rsclient = rn->table->owner;
- afi = rn->table->afi;
- safi = rn->table->safi;
+ dassert((rn->on_wq != 0) && (rn->lock > 0)) ;
+
+ pq->head = rn->wq_next ;
+ rn->wq_next = NULL ; /* Keep tidy */
+ rn->on_wq = 0 ;
+
+ table = rn->table ;
+ rsclient = table->owner;
+ afi = table->afi;
+ safi = table->safi;
+
+ dassert(table->lock > 0) ;
+ dassert(rsclient->lock > 0) ;
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
@@ -1552,8 +1561,8 @@ bgp_process_rsclient (struct work_queue *wq, work_queue_item item)
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
- bgp_table_unlock (rn->table);
bgp_unlock_node (rn);
+ bgp_table_unlock (table); /* NB: *after* node, in case table is deleted */
bgp_unlock (bgp);
if (pq->head == NULL)
@@ -1575,6 +1584,7 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
+ struct bgp_table *table ;
struct peer *peer;
assert(wq->spec.data == item) ;
@@ -1585,11 +1595,18 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
return WQ_SUCCESS ;
/* hack off queue and prepare to process */
- pq->head = rn->wq_next ;
- rn->on_wq = 0 ;
- afi = rn->table->afi;
- safi = rn->table->safi;
+ dassert((rn->on_wq != 0) && (rn->lock > 0)) ;
+
+ pq->head = rn->wq_next ;
+ rn->wq_next = NULL ; /* Keep tidy */
+ rn->on_wq = 0 ;
+
+ table = rn->table ;
+ afi = table->afi;
+ safi = table->safi;
+
+ dassert(table->lock > 0) ;
p = &rn->p ;
@@ -1599,7 +1616,7 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
new_select = old_and_new.new;
/* Nothing to do. */
- if (old_select && old_select == new_select)
+ if (old_select && (old_select == new_select))
{
if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
{
@@ -1626,19 +1643,17 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
}
/* FIB update. */
- if (safi == SAFI_UNICAST && ! bgp->name &&
- ! bgp_option_check (BGP_OPT_NO_FIB))
+ if ((safi == SAFI_UNICAST) && (bgp->name == NULL) &&
+ ! bgp_option_check (BGP_OPT_NO_FIB))
{
- if (new_select
- && new_select->type == ZEBRA_ROUTE_BGP
- && new_select->sub_type == BGP_ROUTE_NORMAL)
+ if (new_select && (new_select->type == ZEBRA_ROUTE_BGP)
+ && (new_select->sub_type == BGP_ROUTE_NORMAL))
bgp_zebra_announce (p, new_select, bgp);
else
{
/* Withdraw the route from the kernel. */
- if (old_select
- && old_select->type == ZEBRA_ROUTE_BGP
- && old_select->sub_type == BGP_ROUTE_NORMAL)
+ if (old_select && (old_select->type == ZEBRA_ROUTE_BGP)
+ && (old_select->sub_type == BGP_ROUTE_NORMAL))
bgp_zebra_withdraw (p, old_select);
}
}
@@ -1650,9 +1665,9 @@ bgp_process_main (struct work_queue *wq, work_queue_item item)
/* Finish up */
finish:
- bgp_table_unlock (rn->table);
- bgp_unlock_node (rn);
- bgp_unlock (bgp);
+ bgp_unlock_node (rn) ;
+ bgp_table_unlock (table) ; /* NB: *after* node, in case table is deleted */
+ bgp_unlock (bgp) ;
if (pq->head == NULL)
return WQ_SUCCESS ;
@@ -1660,6 +1675,9 @@ finish:
return WQ_REQUEUE ;
}
+/*------------------------------------------------------------------------------
+ * Delete item from work queue
+ */
static void
bgp_processq_del (struct work_queue *wq, work_queue_item item)
{
@@ -1670,17 +1688,29 @@ bgp_processq_del (struct work_queue *wq, work_queue_item item)
while ((rn = pq->head) != NULL)
{
- pq->head = rn->wq_next ;
- rn->on_wq = 0 ;
+ struct bgp_table *table ;
+
+ dassert((rn->on_wq != 0) && (rn->lock > 0)) ;
+
+ pq->head = rn->wq_next ;
+ rn->wq_next = NULL ; /* Keep tidy */
+ rn->on_wq = 0 ;
+
+ table = rn->table ;
+
+ dassert(table->lock > 0) ;
- bgp_table_unlock (rn->table);
bgp_unlock_node (rn);
+ bgp_table_unlock (table); /* NB: *after* node, in case table is deleted */
bgp_unlock (pq->bgp);
} ;
wq->spec.data = NULL ;
} ;
+/*------------------------------------------------------------------------------
+ * Create new work queue for given bgp instance and given type of table
+ */
static work_queue
bgp_process_queue_init (struct bgp* bgp, bgp_table_t type)
{
@@ -1718,6 +1748,10 @@ bgp_process_queue_init (struct bgp* bgp, bgp_table_t type)
return *p_wq = wq ;
}
+/*------------------------------------------------------------------------------
+ * Place given route node on appropriate work queue, so that best path
+ * selection etc. can take place later.
+ */
void
bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
{
@@ -1762,9 +1796,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
pq = work_queue_item_args(item) ;
/* all unlocked when processed or deleted */
+ bgp_lock (bgp);
bgp_table_lock (rn->table);
bgp_lock_node (rn);
- bgp_lock (bgp);
/* add to the queue */
if (pq->head == NULL)
@@ -1780,6 +1814,11 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
return;
}
+/*============================================================================*/
+
+/*------------------------------------------------------------------------------
+ * Max Prefix Overflow timer expired -- turn off overflow status and enable.
+ */
static int
bgp_maximum_prefix_restart_timer (struct thread *thread)
{
@@ -1788,15 +1827,42 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_pmax_restart = NULL;
+ assert(CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) ;
+
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("%s Maximum-prefix restart timer expired, restore peering",
peer->host);
- peer_clear (peer);
+ UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+
+ bgp_peer_enable(peer);
return 0;
}
+/*------------------------------------------------------------------------------
+ * If there is an active max prefix restart timer, cancel it now.
+ *
+ * NB: clears PEER_STATUS_PREFIX_OVERFLOW, but does NOT enable the peer.
+ */
+void
+bgp_maximum_prefix_cancel_timer (struct peer *peer)
+{
+ if (peer->t_pmax_restart)
+ {
+ assert(CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) ;
+
+ BGP_TIMER_OFF (peer->t_pmax_restart);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s Maximum-prefix restart timer cancelled", peer->host) ;
+ } ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Number of prefixes has overflowed.
+ */
int
bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
safi_t safi, int always)
@@ -1814,10 +1880,11 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
"%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, "
"limit %ld", afi_safi_print (afi, safi), peer->host,
peer->pcount[afi][safi], peer->pmax[afi][safi]);
+
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
- return 0;
+ return 0;
{
u_int8_t ndata[7];
@@ -1835,8 +1902,8 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
/* Disable the peer, the timer routine will reenable. */
- bgp_notify_send_with_data(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7);
+ bgp_peer_down_error_with_data(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7);
}
/* restart timer start */
@@ -1874,7 +1941,10 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
return 0;
}
-/* Unconditionally remove the route from the RIB, without taking
+/*============================================================================*/
+
+/*------------------------------------------------------------------------------
+ * Unconditionally remove the route from the RIB, without taking
* damping into consideration (eg, because the session went down)
*/
static void
@@ -2671,7 +2741,7 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)
struct bgp_node *rn;
struct bgp_table *table;
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return;
if (! peer->afc_nego[afi][safi])
@@ -2773,7 +2843,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
struct bgp_node *rn;
struct bgp_table *table;
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return;
if (safi != SAFI_MPLS_VPN)
@@ -2790,14 +2860,18 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
*
* There are two (quite different) forms of clearing:
*
- * 1. Normal clearing -- mass withdraw of given client's routes for all
+ * 1. Normal clearing -- mass withdraw of given peer's routes for all
* or individual AFI/SAFI.
*
+ * This is clears the routes *from* the given peer.
+ *
* Note that normal clearing deals with the main RIB and any RS Client
* RIBs that may also contain routes.
*
* 2. RS Client clearing -- dismantling of RS Client RIB for an AFI/SAFI.
*
+ * This clears out the routes *for* the given RS Client.
+ *
*------------------------------------------------------------------------------
* Normal clearing
*
@@ -2834,9 +2908,20 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
* The peer's:
*
* struct bgp_info* routes_head[AFI_MAX][SAFI_MAX] ;
+ *
+ * This list threads through every use of all routes which belong to
+ * the peer, in all RIBs.
+ *
* struct bgp_adj_in* adj_in_head[AFI_MAX][SAFI_MAX] ;
+ *
+ * This list threads through every copy of all routes which belong to the
+ * peer and which have been preserved for soft reconfiguration, in all RIBs.
+ *
* struct bgp_adj_out* adj_out_head[AFI_MAX][SAFI_MAX] ;
*
+ * This list threads through every route which has been selected for the
+ * peer, in all RIBs.
+ *
* Are maintained for exactly this purpose.
*
* NB: this is now a linear process, because the lists identify the stuff to
@@ -2860,6 +2945,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
*
* [The MPLS VPN stuff has a two level RIB, which the above probably doesn't
* work for... more work required, here.]
+ *
* TODO: fix bgp_clear_route() and MPLS VPN !!
*
*------------------------------------------------------------------------------
@@ -2873,28 +2959,226 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
*/
/*------------------------------------------------------------------------------
- * Clear given route -- respecting NSF for peer whose route this is.
+ * Normal clearing of a a given peer's routes.
+ *
+ * The following lists are processed:
+ *
+ * * struct bgp_info* routes_head
+ *
+ * Walks this and clears each route.
+ *
+ * * struct bgp_adj_in* adj_in_head
+ * * struct bgp_adj_out* adj_out_head
+ *
+ * These two are simply emptied out.
+ *
+ * NB: in the latest scheme of things this is completed immediately...
+ *
+ * ...however, retain the ability for this to kick off background or other
+ * activity.
+ *
+ * Returns: true <=> clearing has completed
*
- * Will mark the bgp_info as stale, or will remove altogether. If removes the
- * route will set the bgp_node to be reprocessed.
*/
-static void
-bgp_clear_this_route(bgp_peer peer, struct bgp_node* rn, struct bgp_info* ri,
- afi_t afi, safi_t safi)
-{
- assert (rn && peer && ri) ;
- assert ((rn == ri->rn) && (peer == ri->peer)) ;
-
- /* graceful restart STALE flag set. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)
- && peer->nsf[afi][safi]
- && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
- bgp_info_set_flag (rn, ri, BGP_INFO_STALE);
- else
- bgp_rib_remove (rn, ri, peer, afi, safi);
+extern bool
+bgp_clear_routes(struct peer *peer, afi_t afi, safi_t safi, bool nsf)
+{
+ struct bgp_info* ri ;
+ struct bgp_info* next_ri ;
+ struct bgp_adj_in* adj_in ;
+ struct bgp_adj_out* adj_out ;
+ struct bgp_adj_in** adj_in_head ;
+ struct bgp_adj_out** adj_out_head ;
+
+ next_ri = peer->routes_head[afi][safi] ;
+
+ /* If NSF requested and nsf configured for this afi/safi, do nsf and
+ * set flag to indicate that at least one afi/safi may have stale routes.
+ */
+ nsf = nsf && peer->nsf[afi][safi] ;
+ if (nsf)
+ SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) ;
+
+ /* TODO: fix bgp_clear_route_normal() so can clear an MPLS VPN table.... */
+ if (next_ri != NULL)
+ assert(safi != SAFI_MPLS_VPN) ;
+
+ while (next_ri != NULL)
+ {
+ /* The current bgp_info object may vanish, so bank the next */
+ ri = next_ri ;
+ next_ri = ri->routes_next ;
+
+ assert (peer == ri->peer) ;
+
+ if (nsf && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
+ && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
+ bgp_info_set_flag (ri->rn, ri, BGP_INFO_STALE);
+ else
+ bgp_rib_remove (ri->rn, ri, peer, afi, safi);
+ } ;
+
+ /* Empty out all adjacencies */
+ adj_in_head = &(peer->adj_in_head[afi][safi]) ;
+ while ((adj_in = *adj_in_head) != NULL)
+ {
+ assert(adj_in->route_prev == NULL) ;
+ bgp_adj_in_remove (adj_in->rn, adj_in) ;
+ assert(adj_in != *adj_in_head) ;
+ } ;
+
+ adj_out_head = &(peer->adj_out_head[afi][safi]) ;
+ while ((adj_out = *adj_out_head) != NULL)
+ {
+ assert(adj_out->route_prev == NULL) ;
+ bgp_adj_out_remove (adj_out->rn, adj_out, peer, afi, safi) ;
+ assert(adj_out != *adj_out_head) ;
+ } ;
+
+ return true ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Normal clearing of given peer for all AFI/SAFI -- respecting NSF if required.
+ *
+ * NB: in the latest scheme of things this is completed immediately...
+ *
+ * ...however, retain the ability to run this in the background with the
+ * peer in bgp_peer_pClearing.
+ *
+ * Returns: true <=> all clearing completed
+ * so false => something running in the background.
+ */
+extern bool
+bgp_clear_all_routes (struct peer *peer, bool nsf)
+{
+ bool completed ;
+ afi_t afi;
+ safi_t safi;
+
+ assert(peer->state == bgp_peer_pClearing) ;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) ;
+
+ completed = true ;
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (!bgp_clear_routes(peer, afi, safi, nsf))
+ completed = false ;
+
+ return completed ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Clear Route Server RIB for given AFI/SAFI -- unconditionally
+ *
+ * This is used to dismantle a Route Server Client's RIB -- this is removing
+ * all the routes from all *other* Route Server Clients that have been placed
+ * in this Clients RIB.
+ *
+ * Walks all the nodes in the table and discards all routes, all adj_in and
+ * all adj_out.
+ *
+ * Does nothing if there is no RIB for that AFI/SAFI.
+ */
+extern void
+bgp_clear_rsclient_rib(struct peer* rsclient, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn ;
+ struct bgp_table* table ;
+
+ table = rsclient->rib[afi][safi] ;
+
+ if (table == NULL)
+ return ; /* Ignore unconfigured afi/safi or similar */
+
+ /* TODO: fix bgp_clear_rsclient_rib() so that will clear an MPLS VPN table. */
+ passert(table->safi != SAFI_MPLS_VPN) ;
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ {
+ struct bgp_info *ri;
+ struct bgp_info *next_ri ;
+ struct bgp_adj_in *ain;
+ struct bgp_adj_out *aout;
+
+ next_ri = rn->info ;
+ while(next_ri != NULL)
+ {
+ ri = next_ri ;
+ next_ri = ri->info_next ; /* bank this */
+
+ bgp_rib_remove (rn, ri, rsclient, table->afi, table->safi);
+ } ;
+
+ while ((ain = rn->adj_in) != NULL)
+ {
+ assert(ain->adj_prev == NULL) ;
+ bgp_adj_in_remove (rn, ain);
+ assert(ain != rn->adj_in) ;
+ } ;
+
+ while ((aout = rn->adj_out) != NULL)
+ {
+ assert(aout->adj_prev == NULL) ;
+ bgp_adj_out_remove (rn, aout, aout->peer, table->afi, table->safi) ;
+ assert(aout != rn->adj_out) ;
+ } ;
+ }
+ return ;
+}
+
+/*------------------------------------------------------------------------------
+ * Walk main RIB and remove any adj_in for given peer.
+ *
+ * TODO: walk peer->bgp_adj_in_head[afi][safi] -- but check which table ?
+ */
+void
+bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_table *table;
+ struct bgp_node *rn;
+ struct bgp_adj_in *ain;
+
+ table = peer->bgp->rib[afi][safi];
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ for (ain = rn->adj_in; ain ; ain = ain->adj_next)
+ if (ain->peer == peer)
+ {
+ bgp_adj_in_remove (rn, ain);
+ break;
+ }
} ;
+/*------------------------------------------------------------------------------
+ * Walk main RIB and remove all stale routes for the given peer.
+ *
+ * NB: is required to complete immediately !
+ *
+ * TODO: walk peer->routes_head[afi][safi]
+ */
+void
+bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ struct bgp_info *ri;
+ struct bgp_table *table;
+
+ table = peer->bgp->rib[afi][safi];
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ {
+ for (ri = rn->info; ri; ri = ri->info_next)
+ if (ri->peer == peer)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ bgp_rib_remove (rn, ri, peer, afi, safi);
+ break;
+ }
+ }
+}
+
#if 0
struct bgp_clear_node_queue
@@ -2952,14 +3236,14 @@ bgp_clear_node_complete (struct work_queue *wq)
/* Flush the event queue and ensure the peer is shut down */
bgp_peer_stop(peer);
BGP_EVENT_FLUSH (peer);
- if (peer->state == bgp_peer_sClearing)
+ if (peer->state == bgp_peer_pClearing)
{
- peer_change_status (peer, bgp_peer_sIdle);
+ peer_change_status (peer, bgp_peer_pIdle);
/* enable peer if required */
bgp_peer_enable(peer);
}
- peer_unlock (peer); /* bgp_clear_route */
+ bgp_peer_unlock (peer); /* bgp_clear_route */
}
static void
@@ -2985,120 +3269,6 @@ bgp_clear_node_queue_init (struct peer *peer)
peer->clear_node_queue->spec.data = peer;
}
-#endif
-
-/*------------------------------------------------------------------------------
- * Completely empty the given table which belongs to the given peer.
- *
- * Used for RS Client RIB clearing.
- *
- * Walks the table, *unconditionally* deleting all routes.
- *
- * Deletes any and all adj_in and adj_out.
- *
- * TODO: fix bgp_clear_route_table() so that will clear an MPLS VPN table....
- */
-static void
-bgp_clear_route_table (bgp_peer peer, struct bgp_table* table)
-{
- struct bgp_node *rn ;
-
- if (table == NULL)
- return ; /* Ignore unconfigured afi/safi or similar */
-
- passert(table->safi != SAFI_MPLS_VPN) ;
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- {
- struct bgp_info *ri;
- struct bgp_info *next_ri ;
- struct bgp_adj_in *ain;
- struct bgp_adj_out *aout;
-
- next_ri = rn->info ;
- while(next_ri != NULL)
- {
- ri = next_ri ;
- next_ri = ri->info_next ; /* bank this */
-
- bgp_rib_remove (rn, ri, peer, table->afi, table->safi);
- } ;
-
- while ((ain = rn->adj_in) != NULL)
- {
- assert(ain->adj_prev == NULL) ;
- bgp_adj_in_remove (rn, ain);
- assert(ain != rn->adj_in) ;
- } ;
-
- while ((aout = rn->adj_out) != NULL)
- {
- assert(aout->adj_prev == NULL) ;
- bgp_adj_out_remove (rn, aout, aout->peer, table->afi, table->safi) ;
- assert(aout != rn->adj_out) ;
- } ;
- }
- return ;
-}
-
-/*------------------------------------------------------------------------------
- * Normal clearing of a a given peer's routes.
- *
- * The following lists are processed:
- *
- * * struct bgp_info* routes_head
- *
- * Walks this and clears each route.
- *
- * * struct bgp_adj_in* adj_in_head
- * * struct bgp_adj_out* adj_out_head
- *
- * These two are simply emptied out.
- *
- * TODO: fix bgp_clear_route_normal() so that will clear an MPLS VPN table....
- */
-extern void
-bgp_clear_route_normal(struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_info* ri ;
- struct bgp_info* next_ri ;
- struct bgp_adj_in* adj_in ;
- struct bgp_adj_out* adj_out ;
- struct bgp_adj_in** adj_in_head ;
- struct bgp_adj_out** adj_out_head ;
-
- next_ri = peer->routes_head[afi][safi] ;
-
- assert((safi != SAFI_MPLS_VPN) || (next_ri == NULL)) ;
-
- while (next_ri != NULL)
- {
- /* The current bgp_info object may vanish, so bank the next */
- ri = next_ri ;
- next_ri = ri->routes_next ;
-
- bgp_clear_this_route(peer, ri->rn, ri, afi, safi) ;
- } ;
-
- /* Empty out all adjacencies */
- adj_in_head = &(peer->adj_in_head[afi][safi]) ;
- while ((adj_in = *adj_in_head) != NULL)
- {
- assert(adj_in->route_prev == NULL) ;
- bgp_adj_in_remove (adj_in->rn, adj_in) ;
- assert(adj_in != *adj_in_head) ;
- } ;
-
- adj_out_head = &(peer->adj_out_head[afi][safi]) ;
- while ((adj_out = *adj_out_head) != NULL)
- {
- assert(adj_out->route_prev == NULL) ;
- bgp_adj_out_remove (adj_out->rn, adj_out, peer, afi, safi) ;
- assert(adj_out != *adj_out_head) ;
- } ;
-} ;
-
-#if 0
void
bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
{
@@ -3123,7 +3293,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
* to grow and grow.
*/
//if (!peer->clear_node_queue->thread)
- peer_lock (peer); /* bgp_clear_node_complete */
+ bgp_peer_lock (peer); /* bgp_clear_node_complete */
switch (purpose)
{
@@ -3181,91 +3351,14 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
/* The following was in bgp_clear_node_complete */
- peer_unlock (peer); /* bgp_clear_route */
+ bgp_peer_unlock (peer); /* bgp_clear_route */
}
#endif
-/*------------------------------------------------------------------------------
- * Clear Route Server RIB for given AFI/SAFI -- unconditionally
- *
- * Does nothing if there is no RIB for that AFI/SAFI.
- */
-extern void
-bgp_clear_route_rsclient(struct peer* rsclient, afi_t afi, safi_t safi)
-{
- bgp_clear_route_table (rsclient, rsclient->rib[afi][safi]) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Normal clearing of given peer for all AFI/SAFI -- respecting NSF.
- *
- * NB: in the latest scheme of things this is completed immediately...
- *
- * ...however, retain the ability to run this in the background with the
- * peer in bgp_peer_sClearing.
- *
- * Caller should set state of peer *before* calling this.
- */
-extern void
-bgp_clear_route_all (struct peer *peer)
-{
- afi_t afi;
- safi_t safi;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- bgp_clear_route_normal(peer, afi, safi);
-
- bgp_peer_clearing_completed(peer) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Walk main RIB and remove all adj_in for given peer.
- */
-void
-bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_table *table;
- struct bgp_node *rn;
- struct bgp_adj_in *ain;
-
- table = peer->bgp->rib[afi][safi];
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (ain = rn->adj_in; ain ; ain = ain->adj_next)
- if (ain->peer == peer)
- {
- bgp_adj_in_remove (rn, ain);
- break;
- }
-}
-
-/*------------------------------------------------------------------------------
- * Walk main RIB and remove all stale routes for the given peer.
- */
-void
-bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_node *rn;
- struct bgp_info *ri;
- struct bgp_table *table;
-
- table = peer->bgp->rib[afi][safi];
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- {
- for (ri = rn->info; ri; ri = ri->info_next)
- if (ri->peer == peer)
- {
- if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- bgp_rib_remove (rn, ri, peer, afi, safi);
- break;
- }
- }
-}
/*============================================================================*/
-/* Delete all kernel routes. */
+#if 0
+/* Delete all kernel routes. */
void
bgp_cleanup_routes (void)
{
@@ -3296,6 +3389,7 @@ bgp_cleanup_routes (void)
bgp_zebra_withdraw (&rn->p, ri);
}
}
+#endif
void
bgp_reset (void)
@@ -3317,7 +3411,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
int ret;
/* Check peer status. */
- if (peer->state != bgp_peer_sEstablished)
+ if (peer->state != bgp_peer_pEstablished)
return 0;
pnt = packet->nlri;
@@ -3432,8 +3526,8 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
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);
+ bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
@@ -3446,8 +3540,8 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
"%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);
+ bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
@@ -3461,8 +3555,8 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
"%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);
+ bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
return 0;
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 97ee39ab..e1e8f18d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -174,7 +174,7 @@ enum bgp_clear_route_type
/* Prototypes. */
extern void bgp_route_init (void);
extern void bgp_route_finish (void);
-extern void bgp_cleanup_routes (void);
+
extern void bgp_announce_route (struct peer *, afi_t, safi_t);
extern void bgp_announce_route_all (struct peer *);
extern void bgp_default_originate (struct peer *, afi_t, safi_t, int);
@@ -182,10 +182,11 @@ extern void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t);
extern void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t);
extern void bgp_check_local_routes_rsclient (struct peer *rsclient,
afi_t afi, safi_t safi);
-extern void bgp_clear_route_normal(struct peer *peer, afi_t afi, safi_t safi) ;
-extern void bgp_clear_route_rsclient(struct peer* rsclient,
+extern bool bgp_clear_routes(struct peer *peer, afi_t afi, safi_t safi,
+ bool nsf) ;
+extern void bgp_clear_rsclient_rib(struct peer* rsclient,
afi_t afi, safi_t safi) ;
-extern void bgp_clear_route_all (struct peer *);
+extern bool bgp_clear_all_routes (struct peer *, bool nsf);
extern void bgp_clear_adj_in (struct peer *, afi_t, safi_t);
extern void bgp_clear_stale_route (struct peer *, afi_t, safi_t);
@@ -201,6 +202,7 @@ extern int bgp_nlri_sanity_check (struct peer *, int, 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);
+extern void bgp_maximum_prefix_cancel_timer (struct peer *peer) ;
extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t,
u_char);
diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c
index 8d8bfea2..9de8678a 100644
--- a/bgpd/bgp_session.c
+++ b/bgpd/bgp_session.c
@@ -40,7 +40,6 @@
#include "lib/zassert.h"
/* prototypes */
-static int bgp_session_defer_if_limping(bgp_session session);
static void bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) ;
static void bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag);
static void bgp_session_do_update_send(mqueue_block mqb, mqb_flag_t flag);
@@ -99,7 +98,7 @@ static void bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag)
*/
/*------------------------------------------------------------------------------
- * Initialise new session structure -- allocate if required.
+ * Allocate & initialise new session structure.
*
* Ties peer and session together. Sets session sIdle, initialises mutex.
*
@@ -108,30 +107,34 @@ static void bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag)
* NB: if not allocating, the existing session MUST be sIdle/sDisabled OR never
* been kissed.
*
- * NB: in any event, the peer's peer index entry MUST have a NULL accept
- * pointer.
+ * NB: peer MUST NOT have a session set up:
+ *
+ * (a) because if there was a session, there would have to be code here
+ * to worry about its state, and tearing it down etc.
+ *
+ * (b) so that do not have to worry about BGP Engine reaching the old
+ * session while it was being replaced or whatever.
*/
extern bgp_session
-bgp_session_init_new(bgp_session session, bgp_peer peer)
+bgp_session_init_new(bgp_peer peer)
{
+ bgp_session session ;
+
assert(peer->session == NULL) ;
- assert(peer->index_entry->accept == NULL) ;
- if (session == NULL)
- session = XCALLOC(MTYPE_BGP_SESSION, sizeof(struct bgp_session)) ;
- else
- memset(session, 0, sizeof(struct bgp_session)) ;
+ session = XCALLOC(MTYPE_BGP_SESSION, sizeof(struct bgp_session)) ;
qpt_mutex_init_new(&session->mutex, qpt_mutex_recursive) ;
- peer->session = session ;
session->peer = peer ;
- session->state = bgp_session_sIdle ;
+ bgp_peer_lock(peer) ; /* Account for the session->peer pointer */
- session->index_entry = peer->index_entry ;
+ session->state = bgp_session_sIdle ;
/* Zeroising the structure has set:
*
+ * delete_me -- 0 -- false
+ *
* event -- bgp_session_null_event
* notification -- NULL -- none
* err -- 0 -- none
@@ -173,25 +176,73 @@ bgp_session_init_new(bgp_session session, bgp_peer peer)
*
* connections[] -- NULL -- none
* active -- false, not yet active
+ * accept -- false, not yet ready to accept()
*/
confirm(bgp_session_null_event == 0) ;
+ /* Once the session is fully initialised, can set peer->session pointer.
+ *
+ * NB: this is done last and under the Peer Index Mutex, so that the
+ * accept() code does not trip over.
+ */
+ bgp_peer_index_set_session(peer, session) ;
+
return session ;
} ;
-/* Free session structure
+/*==============================================================================
+ * Routing Engine: delete session for given peer.
+ *
+ * This is for use when the peer itself is being deleted. (Peer MUST be in
+ * pDeleting state.)
+ *
+ * Does nothing if there is no session !
+ *
+ * If the session is active, simply sets delete_me flag, which will be honoured
+ * when the session goes dDisabled. Note, it is the callers responsibility
+ * to arrange for that to happen.
+ *
+ * If the session is not active, it is immediately freed.
*
+ * NB: if the session is freed, the peer may vanish at the same time !
*/
-extern bgp_session
-bgp_session_free(bgp_session session)
+extern void
+bgp_session_delete(bgp_peer peer)
{
+ bgp_session session = peer->session ;
+
if (session == NULL)
- return NULL;
+ return ; /* easy if no session anyway */
+
+ assert(peer == session->peer) ;
+
+ /* If is active, set flag so that session is deleted when next it becomes
+ * sDisabled.
+ */
+ if (bgp_session_is_active(session))
+ {
+ session->delete_me = true ;
+ return ;
+ } ;
+
+ /*--------------------------------------------------------------------------*/
+ /* Proceed to free the session structure. */
+
+ /* Make sure that the BGP Engine has, in fact, let go of the session.
+ *
+ * The LOCK/UNLOCK makes sure that the BGP Engine has unlocked the session.
+ *
+ * Without this, the qpt_mutex_destroy() can fail horribly, if the BGP
+ * Engine sends the disable acknowledge before finally unlocking the session.
+ */
+ BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- assert(!bgp_session_is_active(session)) ;
+ BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
qpt_mutex_destroy(&session->mutex, 0) ;
+ /* Proceed to dismantle the session. */
+
bgp_notify_unset(&session->notification);
bgp_open_state_free(session->open_send);
bgp_open_state_free(session->open_recv);
@@ -206,12 +257,24 @@ bgp_session_free(bgp_session session)
sockunion_unset(&session->su_local) ;
sockunion_unset(&session->su_remote) ;
+ /* Drop the peer->session and session->peer pointers
+ *
+ * NB: the peer->session pointer is cleared under the Peer Index Mutex,
+ * so that the accept() code does not trip over.
+ *
+ * NB: at this point it is possible for the peer structure to suddenly
+ * vanish -- if peer has been deleted, and has been waiting for the
+ * session to go sDisabled.
+ */
+ bgp_peer_index_set_session(peer, NULL) ;
+
+ session->peer = NULL ;
+ bgp_peer_unlock(peer) ; /* NB: peer->session == NULL */
+
/* Zeroize to catch dangling references asap */
memset(session, 0, sizeof(struct bgp_session)) ;
XFREE(MTYPE_BGP_SESSION, session);
-
- return NULL;
-}
+} ;
/*==============================================================================
* Routing Engine: enable session for given peer -- allocate if required.
@@ -226,6 +289,8 @@ bgp_session_enable(bgp_peer peer)
bgp_session session ;
mqueue_block mqb ;
+ assert(peer->state = bgp_peer_pIdle) ;
+
/* Set up session if required. Check session if already exists.
*
* Only the Routing Engine creates sessions, so it is safe to pick up the
@@ -238,27 +303,24 @@ bgp_session_enable(bgp_peer peer)
session = peer->session ;
if (session == NULL)
- session = bgp_session_init_new(NULL, peer) ;
+ session = bgp_session_init_new(peer) ;
else
{
assert(session->peer == peer) ;
- /* if session is limping then defer the enable */
- if (bgp_session_defer_if_limping(session))
- return;
assert(!bgp_session_is_active(session)) ;
} ;
/* Initialise what we need to make and run connections */
- session->state = bgp_session_sIdle;
- session->defer_enable = 0;
- session->flow_control = 0;
- session->event = bgp_session_null_event;
- bgp_notify_unset(&session->notification);
- session->err = 0;
- session->ordinal = 0;
+ session->state = bgp_session_sIdle ;
+ session->delete_me = false ;
+ session->flow_control = 0 ;
+ session->event = bgp_session_null_event ;
+ bgp_notify_unset(&session->notification) ;
+ session->err = 0 ;
+ session->ordinal = 0 ;
- session->open_send = bgp_peer_open_state_init_new(session->open_send, peer);
- bgp_open_state_unset(&session->open_recv);
+ session->open_send = bgp_peer_open_state_init_new(session->open_send, peer) ;
+ bgp_open_state_unset(&session->open_recv) ;
session->connect = (peer->flags & PEER_FLAG_PASSIVE) == 0 ;
session->listen = 1 ;
@@ -306,12 +368,22 @@ bgp_session_enable(bgp_peer peer)
session->hold_timer_interval = peer->v_holdtime ;
session->keepalive_timer_interval = peer->v_keepalive ;
- session->as4 = 0;
- session->route_refresh_pre = 0;
+ session->as4 = false ;
+ session->route_refresh_pre = false ;
+ session->orf_prefix_pre = false ;
/* su_local set when session Established */
/* su_remote set when session Established */
+ /* TODO: check whether session stats should persist */
+ memset(&session->stats, 0, sizeof(struct bgp_session_stats)) ;
+
+ memset(&session->connections, 0,
+ sizeof(bgp_connection) * bgp_connection_count) ;
+
+ session->active = false ;
+ session->accept = false ;
+
/* Routeing Engine does the state change now. */
/* Now pass the session to the BGP Engine, which will set about */
@@ -340,7 +412,7 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag)
BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- session->active = 1 ;
+ session->active = true ;
bgp_fsm_enable_session(session) ;
BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
@@ -352,6 +424,8 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag)
/*==============================================================================
* Routing Engine: disable session for given peer -- if enabled (!).
*
+ * Does nothing if the session is not sEnabled or sEstablished.
+ *
* Passes any bgp_notify to the BGP Engine, which will dispose of it in due
* course.
*
@@ -390,7 +464,6 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification)
/* Now change to limping state */
session->state = bgp_session_sLimping;
- session->defer_enable = 0;
/* Ask the BGP engine to disable the session.
*
@@ -470,7 +543,10 @@ bgp_session_event(bgp_session session, bgp_session_event_t event,
mqueue_block mqb ;
if (stopped)
- session->active = 0 ; /* ignore updates etc */
+ {
+ session->active = false ; /* ignore updates etc */
+ session->accept = false ; /* for completeness */
+ } ;
mqb = mqb_init_new(NULL, bgp_session_do_event, session) ;
@@ -774,6 +850,8 @@ bgp_session_update_recv(bgp_session session, struct stream* buf, bgp_size_t size
/*------------------------------------------------------------------------------
* Routing Engine: process incoming update message -- mqb action function.
+ *
+ * Discard the update if the session is not sEstablished.
*/
static void
bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag)
@@ -781,10 +859,9 @@ bgp_session_do_update_recv(mqueue_block mqb, mqb_flag_t flag)
bgp_session session = mqb_get_arg0(mqb) ;
struct bgp_session_update_args* args = mqb_get_args(mqb) ;
- if ((flag == mqb_action) && (session->state == bgp_session_sEstablished))
+ if ( (flag == mqb_action) && (session->state == bgp_session_sEstablished) )
{
- bgp_peer peer = session->peer;
-
+ bgp_peer peer = session->peer;
stream_free(peer->ibuf);
peer->ibuf = args->buf;
bgp_update_receive (peer, args->size);
@@ -826,8 +903,8 @@ bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag)
struct bgp_session_route_refresh_args* args = mqb_get_args(mqb) ;
bgp_session session = mqb_get_arg0(mqb) ;
- if ((flag == mqb_action) && (session->state == bgp_session_sEstablished))
- bgp_route_refresh_recv(session->peer, args->rr);
+ if ( (flag == mqb_action) && (session->state == bgp_session_sEstablished) )
+ bgp_route_refresh_recv(session->peer, args->rr) ;
bgp_route_refresh_free(args->rr);
mqb_free(mqb);
@@ -860,9 +937,10 @@ bgp_session_do_XON(mqueue_block mqb, mqb_flag_t flag)
{
bgp_session session = mqb_get_arg0(mqb) ;
- if ((flag == mqb_action) && (session->state == bgp_session_sEstablished))
+ if ( (flag == mqb_action) && (session->state == bgp_session_sEstablished) )
{
int xoff = (session->flow_control <= 0);
+
session->flow_control = BGP_XON_REFRESH;
if (xoff)
bgp_write (session->peer, NULL) ;
@@ -923,59 +1001,46 @@ bgp_session_do_set_ttl(mqueue_block mqb, mqb_flag_t flag)
*/
/*------------------------------------------------------------------------------
- * See if session exists and is active.
+ * Routing Engine: see if session exists and is active.
*
- * Ensure that if exists and is not active, that the peer index entry accept
- * pointer is NULL -- this is largely paranoia, but it would be a grave
- * mistake for the listening socket(s) to find a session which is not active !
+ * If exists then performs a few checks, just to make sure things are straight.
*
- * NB: accessing Routing Engine "private" variable -- no lock required.
+ * NB: accessing Routing Engine "private" variable -- no lock required.
*
- * accessing index_entry when not active -- no lock required.
+ * checks session->active, only when not active -- no lock required.
*/
-extern int
+extern bool
bgp_session_is_active(bgp_session session)
{
- int active ;
+ bool active ;
if (session == NULL)
- active = 0 ;
+ active = false ;
else
{
- active = ( (session->state == bgp_session_sEnabled)
- || (session->state == bgp_session_sEstablished)
- || (session->state == bgp_session_sLimping) ) ;
-
- if (!active)
- assert(session->index_entry->accept == NULL) ;
+ switch (session->state)
+ {
+ case bgp_session_sIdle:
+ case bgp_session_sDisabled:
+ assert(!session->active) ;
+ active = false ;
+ break ;
+
+ case bgp_session_sEnabled:
+ case bgp_session_sEstablished:
+ case bgp_session_sLimping:
+ active = true ;
+ break ;
+
+ default:
+ zabort("invalid session->state") ;
+ } ;
} ;
return active ;
} ;
/*------------------------------------------------------------------------------
- * Routing Engine: if session is limping we defer re-enabling the session
- * until it is disabled.
- *
- * returns 1 if limping and defer
- * returns 0 if not limping
- *
- * NB: accessing Routing Engine "private" variable -- no lock required.
- */
-static int
-bgp_session_defer_if_limping(bgp_session session)
-{
- int defer_enable = 0 ;
-
- if (session == NULL)
- defer_enable = 0 ;
- else
- defer_enable = (session->state == bgp_session_sLimping) ;
-
- return session->defer_enable = defer_enable ;
-} ;
-
-/*------------------------------------------------------------------------------
* Get a copy of the session statistics, copied all at once so
* forms a consistent snapshot
*/
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index 6f449bec..79b6f1a4 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -89,23 +89,22 @@ struct bgp_session_stats
struct bgp_session
{
- /* The following are set when the session is created, and not changed
- * thereafter.
+ /* The following is set when the session is created, and not changed
+ * thereafter, so do not need to lock the session to access this.
*/
bgp_peer peer ; /* peer whose session this is */
- bgp_peer_index_entry index_entry ; /* and its index entry */
/* This is a *recursive* mutex */
qpt_mutex_t mutex ; /* for access to the rest */
- /* While sIdle and sStopped:
+ /* While sIdle and sDisabled -- aka not "active" states:
*
* the session belongs to the Routing Engine.
*
* The BGP Engine will not touch a session in these states and the
* Routing Engine may do what it likes with it.
*
- * While sEnabled, sEstablished and sStopping:
+ * While sEnabled, sEstablished and sLimping -- aka "active" states:
*
* the session belongs to the BGP Engine.
*
@@ -119,11 +118,12 @@ struct bgp_session
* These are private to the Routing Engine.
*/
bgp_session_state_t state ;
- int defer_enable ; /* set when waiting for stop */
int flow_control ; /* limits number of updates sent
by the Routing Engine */
+ bool delete_me ; /* when next goes sDisabled */
+
/* These are private to the Routing Engine, and are set each time a session
* event message is received from the BGP Engine.
*/
@@ -211,10 +211,15 @@ struct bgp_session
* and enable are ignored. This deals with the hiatus that exists between
* the BGP Engine signalling that it has stopped (because of some exception)
* and the Routing Engine acknowledging that (by disabling the session).
+ *
+ * The accept flag is set when the secondary connection is completely ready
+ * to accept connections. It is cleared otherwise, or when the active flag
+ * is cleared.
*/
bgp_connection connections[bgp_connection_count] ;
bool active ;
+ bool accept ;
} ;
/*==============================================================================
@@ -267,7 +272,7 @@ MQB_ARGS_SIZE_OK(bgp_session_end_of_rib_args) ;
struct bgp_session_event_args /* to Routeing Engine */
{
- bgp_session_event_t event ;
+ bgp_session_event_t event ; /* what just happened */
bgp_notify notification ; /* sent or received (if any) */
int err ; /* errno if any */
bgp_connection_ord_t ordinal ; /* primary/secondary connection */
@@ -309,10 +314,7 @@ inline static void BGP_SESSION_UNLOCK(bgp_session session)
*/
extern bgp_session
-bgp_session_init_new(bgp_session session, bgp_peer peer) ;
-
-extern bgp_session
-bgp_session_free(bgp_session session);
+bgp_session_init_new(bgp_peer peer) ;
extern void
bgp_session_enable(bgp_peer peer) ;
@@ -321,6 +323,9 @@ extern void
bgp_session_disable(bgp_peer peer, bgp_notify notification) ;
extern void
+bgp_session_delete(bgp_peer peer);
+
+extern void
bgp_session_event(bgp_session session, bgp_session_event_t event,
bgp_notify notification,
int err,
@@ -358,7 +363,7 @@ bgp_session_get_stats(bgp_session session, struct bgp_session_stats *stats);
* Session data access functions.
*/
-extern int
+extern bool
bgp_session_is_active(bgp_session session) ;
#endif /* QUAGGA_BGP_SESSION_H */
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 91cab606..a2581e3c 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -96,6 +96,7 @@ bgp_node_set (struct bgp_table *table, struct prefix *prefix)
static void
bgp_node_free (struct bgp_node *node)
{
+ node->lock = -54321 ;
XFREE (MTYPE_BGP_NODE, node);
}
@@ -128,11 +129,17 @@ bgp_table_free (struct bgp_table *rt)
continue;
}
+ assert( (node->info == NULL)
+ && (node->adj_out == NULL)
+ && (node->adj_in == NULL)
+ && (node->on_wq == 0) ) ;
+
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)
@@ -152,10 +159,11 @@ bgp_table_free (struct bgp_table *rt)
if (rt->owner)
{
- peer_unlock (rt->owner);
+ bgp_peer_unlock (rt->owner);
rt->owner = NULL;
}
+ rt->lock = -54321 ;
XFREE (MTYPE_BGP_TABLE, rt);
return;
}
@@ -371,6 +379,7 @@ bgp_node_delete (struct bgp_node *node)
assert (node->lock == 0);
assert (node->info == NULL);
+ assert (node->on_wq == 0) ;
if (node->l_left && node->l_right)
return;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 1afc9f94..2a5acb05 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1353,7 +1353,7 @@ DEFUN (no_neighbor,
{
peer = peer_lookup (vty->index, &su);
if (peer)
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
return CMD_SUCCESS;
@@ -1794,7 +1794,7 @@ DEFUN (no_neighbor_dont_capability_negotiate,
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)
+ safi_t safi, u_int32_t flag, bool set)
{
int ret;
struct peer *peer;
@@ -1803,10 +1803,7 @@ peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi,
if (! peer)
return CMD_WARNING;
- if (set)
- ret = peer_af_flag_set (peer, afi, safi, flag);
- else
- ret = peer_af_flag_unset (peer, afi, safi, flag);
+ ret = peer_af_flag_modify(peer, afi, safi, flag, set);
return bgp_vty_return (vty, ret);
}
@@ -1815,14 +1812,14 @@ static int
peer_af_flag_set_vty (struct vty *vty, const char *peer_str, afi_t afi,
safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1);
+ return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, true);
}
static int
peer_af_flag_unset_vty (struct vty *vty, const char *peer_str, afi_t afi,
safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0);
+ return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, false);
}
/* neighbor capability orf prefix-list. */
@@ -2080,7 +2077,7 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
struct listnode *node, *nnode;
struct bgp_filter *pfilter;
struct bgp_filter *gfilter;
- int locked_and_added = 0;
+ bool was_active ;
bgp = vty->index;
@@ -2092,29 +2089,22 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) )
return CMD_SUCCESS;
- if ( ! peer_rsclient_active (peer) )
- {
- peer = peer_lock (peer); /* rsclient peer list reference */
- listnode_add_sort (bgp->rsclient, peer);
- locked_and_added = 1;
- }
+ was_active = peer_rsclient_active(peer) ;
ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT);
if (ret < 0)
- {
- if (locked_and_added)
- {
- listnode_delete (bgp->rsclient, peer);
- peer_unlock (peer); /* rsclient peer list reference */
- }
+ return bgp_vty_return (vty, ret);
- return bgp_vty_return (vty, ret);
- }
+ if (!was_active)
+ {
+ bgp_peer_lock (peer); /* rsclient peer list reference */
+ listnode_add_sort (bgp->rsclient, peer);
+ } ;
peer->rib[afi][safi] = bgp_table_init (afi, safi);
peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT;
/* RIB peer reference. Released when table is free'd in bgp_table_free. */
- peer->rib[afi][safi]->owner = peer_lock (peer);
+ peer->rib[afi][safi]->owner = bgp_peer_lock (peer);
/* Check for existing 'network' and 'redistribute' routes. */
bgp_check_local_routes_rsclient (peer, afi, safi);
@@ -2181,10 +2171,19 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
if ( ! peer )
return CMD_WARNING;
+ assert(bgp == peer->bgp) ;
+
/* If it is not a RS-Client, don't do anything. */
if ( ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) )
return CMD_SUCCESS;
+ /* If this is a Peer Group, then need to undo the relevant rsclient state
+ * for all the group members.
+ *
+ * That means clearing the state flag and the pointer to the shared RIB.
+ *
+ * TODO: peer_af_flag_unset PEER_FLAG_RSERVER_CLIENT fails for group members ?
+ */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
{
group = peer->group;
@@ -2201,20 +2200,63 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
peer = group->conf;
}
+ /* Unset the rsclient flag and remove from rsclient list if no longer a
+ * distinct rsclient.
+ *
+ * NB: this takes care of downing the peer, if required.
+ */
ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT);
if (ret < 0)
return bgp_vty_return (vty, ret);
- if ( ! peer_rsclient_active (peer) )
+ /* Now tidy up the data structures. */
+ peer_rsclient_unset(peer, afi, safi, false) ;
+
+ return CMD_SUCCESS;
+}
+
+/* Have unset rsclient state for a peer that was a distinct rsclient.
+ *
+ * Tidy up the data structures.
+ *
+ * NB: does not down the peer or deal with other consequences.
+ */
+void
+peer_rsclient_unset(struct peer* peer, int afi, int safi, bool keep_export)
+{
+ assert(peer->rib[afi][safi] != NULL) ;
+
+ /* If the peer is no longer a distinct rsclient, remove from list of same. */
+ if (! peer_rsclient_active (peer))
{
- bgp_clear_route_rsclient (peer, afi, safi);
- listnode_delete (bgp->rsclient, peer);
- peer_unlock (peer); /* peer bgp rsclient reference */
+ struct listnode *pn;
+ pn = listnode_lookup (peer->bgp->rsclient, peer) ;
+
+ assert(pn != NULL) ;
+
+ bgp_peer_unlock (peer); /* peer rsclient reference */
+ list_delete_node (peer->bgp->rsclient, pn);
}
- bgp_table_finish (&peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]);
+ /* Discard the rsclient rib */
+ bgp_clear_rsclient_rib (peer, afi, safi);
+ bgp_table_finish (&peer->rib[afi][safi]);
- return CMD_SUCCESS;
+ /* Discard import policy unconditionally */
+ if (peer->filter[afi][safi].map[RMAP_IMPORT].name)
+ {
+ free (peer->filter[afi][safi].map[RMAP_IMPORT].name);
+ peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL;
+ peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL;
+ }
+
+ /* Discard export policy unless should be kept. */
+ if (peer->filter[afi][safi].map[RMAP_EXPORT].name && !keep_export)
+ {
+ free (peer->filter[afi][safi].map[RMAP_EXPORT].name);
+ peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL;
+ peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL;
+ }
}
/* neighbor route-server-client. */
@@ -6778,7 +6820,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
vty_out (vty, "%8s",
peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
- if (peer->state == bgp_peer_sEstablished)
+ if (peer->state == bgp_peer_pEstablished)
{
vty_out (vty, " %8ld", peer->pcount[afi][safi]);
}
@@ -7315,7 +7357,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* Status. */
vty_out (vty, " BGP state = %s",
LOOKUP (bgp_peer_status_msg, p->state));
- if (p->state == bgp_peer_sEstablished)
+ if (p->state == bgp_peer_pEstablished)
vty_out (vty, ", up for %8s",
peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN));
/* TODO: what is state "Active" now? sEnabled? */
@@ -7344,7 +7386,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
}
/* Capability. */
- if (p->state == bgp_peer_sEstablished)
+ if (p->state == bgp_peer_pEstablished)
{
if (p->cap
|| p->afc_adv[AFI_IP][SAFI_UNICAST]
@@ -7466,7 +7508,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
int eor_receive_af_count = 0;
vty_out (vty, " Graceful restart informations:%s", VTY_NEWLINE);
- if (p->state == bgp_peer_sEstablished)
+ if (p->state == bgp_peer_pEstablished)
{
vty_out (vty, " End-of-RIB send: ");
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index c0fc3628..195ccaef 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -167,7 +167,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length)
continue;
if (ifp == peer_if)
- bgp_peer_disable(peer, NULL);
+ bgp_peer_down(peer, PEER_DOWN_INTERFACE_DOWN);
}
}
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 1176d2d0..dfcc7ff0 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -80,9 +80,6 @@ qpn_nexus routing_nexus = NULL;
/* BGP community-list. */
struct community_list_handler *bgp_clist;
-/* true while program terminating */
-static int program_terminating = 0;
-
/* BGP global flag manipulation. */
int
bgp_option_set (int flag)
@@ -183,13 +180,7 @@ bgp_router_id_set (struct bgp *bgp, struct in_addr *id)
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
IPV4_ADDR_COPY (&peer->local_id, id);
-
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->last_reset = PEER_DOWN_RID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
+ bgp_peer_down(peer, PEER_DOWN_RID_CHANGE) ;
}
return 0;
}
@@ -214,12 +205,7 @@ bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id)
if (peer_sort (peer) != BGP_PEER_IBGP)
continue;
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->last_reset = PEER_DOWN_CLID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
+ bgp_peer_down(peer, PEER_DOWN_CLID_CHANGE) ;
}
return 0;
}
@@ -242,12 +228,7 @@ bgp_cluster_id_unset (struct bgp *bgp)
if (peer_sort (peer) != BGP_PEER_IBGP)
continue;
- if (peer->state == bgp_peer_sEstablished)
- {
- peer->last_reset = PEER_DOWN_CLID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
+ bgp_peer_down(peer, PEER_DOWN_CLID_CHANGE) ;
}
return 0;
}
@@ -267,7 +248,7 @@ int
bgp_timers_unset (struct bgp *bgp)
{
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
- bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
+ bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
return 0;
}
@@ -300,23 +281,20 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
if (peer_sort (peer) == BGP_PEER_EBGP)
{
peer->local_as = as;
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
}
}
else
{
- /* Not doign confederation before, so reset every non-local
+ /* Not doing confederation before, so reset every non-local
session */
if (peer_sort (peer) != BGP_PEER_IBGP)
{
/* Reset the local_as to be our EBGP one */
if (peer_sort (peer) == BGP_PEER_EBGP)
peer->local_as = as;
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+
+ bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
}
}
}
@@ -338,9 +316,7 @@ bgp_confederation_id_unset (struct bgp *bgp)
if (peer_sort (peer) != BGP_PEER_IBGP)
{
peer->local_as = bgp->as;
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
}
}
return 0;
@@ -396,9 +372,7 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as)
if (peer->as == as)
{
peer->local_as = bgp->as;
- peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_PEER_CHANGE) ;
}
}
}
@@ -447,9 +421,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
if (peer->as == as)
{
peer->local_as = bgp->confed_id;
- peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_CONFED_PEER_CHANGE) ;
}
}
}
@@ -535,7 +507,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
filter->aslist[i].name = NULL;
}
}
- for (i = RMAP_IN; i < RMAP_MAX; i++)
+ for (i = RMAP_IN; i < RMAP_MAX; i++)
{
if (filter->map[i].name)
{
@@ -664,59 +636,15 @@ peer_sort (struct peer *peer)
}
}
-
-/* increase reference count on a struct peer */
-struct peer *
-peer_lock (struct peer *peer)
-{
- assert (peer && (peer->lock >= 0));
-
- peer->lock++;
-
- return peer;
-}
-
-/* decrease reference count on a struct peer
- * struct peer is freed and NULL returned if last reference
- */
-struct peer *
-peer_unlock (struct peer *peer)
-{
- assert (peer && (peer->lock > 0));
-
- 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;
-}
-
-
/* Make accept BGP peer. Called from bgp_accept (). */
struct peer *
peer_create_accept (struct bgp *bgp)
{
struct peer *peer;
- peer = peer_new (bgp);
+ peer = bgp_peer_new (bgp);
- peer = peer_lock (peer); /* bgp peer list reference */
+ peer = bgp_peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
return peer;
@@ -728,13 +656,6 @@ peer_as_change (struct peer *peer, as_t as)
{
int type;
- /* Stop peer. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
type = peer_sort (peer);
peer->as = as;
@@ -772,12 +693,16 @@ peer_as_change (struct peer *peer, as_t as)
PEER_FLAG_REFLECTOR_CLIENT);
}
- /* local-as reset */
+ /* local-as reset */
if (peer_sort (peer) != BGP_PEER_EBGP)
{
peer->change_local_as = 0;
UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
}
+
+ /* Down peer. */
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ bgp_peer_down(peer, PEER_DOWN_REMOTE_AS_CHANGE) ;
}
/* If peer does not exist, create new one. If peer already exists,
@@ -836,14 +761,16 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
else
local_as = bgp->as;
- /* If this is IPv4 unicast configuration and "no bgp default
- ipv4-unicast" is specified. */
+ /* TODO: report bug... if is IPv4 unicast, may implicitly activate */
- 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);
+ /* If this is IPv4 unicast configuration and "no bgp default
+ ipv4-unicast" is NOT specified.
+ */
+ if (!bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
+ && (afi == AFI_IP) && (safi == SAFI_UNICAST))
+ peer = bgp_peer_create (su, bgp, local_as, *as, afi, safi);
else
- peer = peer_create (su, bgp, local_as, *as, afi, safi);
+ peer = bgp_peer_create (su, bgp, local_as, *as, 0, 0);
}
return 0;
@@ -853,7 +780,7 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
int
peer_activate (struct peer *peer, afi_t afi, safi_t safi)
{
- int active;
+ bool was_active;
if (peer->afc[afi][safi])
return 0;
@@ -863,15 +790,19 @@ peer_activate (struct peer *peer, afi_t afi, safi_t safi)
peer->afc[afi][safi] = 1;
else
{
- active = peer_active (peer);
-
+ was_active = peer_active (peer);
peer->afc[afi][safi] = 1;
- if (! active && peer_active (peer))
+ /* If wasn't active, can now enable since now is.
+ *
+ * Otherwise, to enable an extra AFI/SAFI need either to use Dynamic
+ * Capabilities or restart the session.
+ */
+ if (! was_active)
bgp_peer_enable (peer);
else
-#if 0
/* TODO: Dynamic capability */
+#if 0
{
if (peer->status == Established)
{
@@ -890,9 +821,7 @@ peer_activate (struct peer *peer, afi_t afi, safi_t safi)
else
#endif
{
- peer->last_reset = PEER_DOWN_AF_ACTIVATE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_AF_ACTIVATE) ;
}
#if 0
}
@@ -905,17 +834,19 @@ peer_activate (struct peer *peer, afi_t afi, safi_t safi)
int
peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
- struct peer *peer1;
- struct listnode *node, *nnode;
+ bool was_rsclient ;
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer* group_member ;
+
group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, group_member))
{
- if (peer1->af_group[afi][safi])
+ if (group_member->af_group[afi][safi])
return BGP_ERR_PEER_GROUP_MEMBER_EXISTS;
}
}
@@ -928,53 +859,56 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
if (! peer->afc[afi][safi])
return 0;
- /* De-activate the address family configuration. */
+ /* If we arrive here, the peer is either:
+ *
+ * - a real peer which is not a group member for this afi/safi
+ *
+ * - a group which has no members for this afi/safi.
+ *
+ * In which case, if this is an rsclient, it is a distinct rsclient, and the
+ * rsclient RIB should be discarded.
+ */
+ was_rsclient = CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT) ;
+
+ /* De-activate the address family configuration. */
peer->afc[afi][safi] = 0;
peer_af_flag_reset (peer, afi, safi);
+ /* Tidy up if was rsclient */
+ if (was_rsclient)
+ peer_rsclient_unset(peer, afi, safi, false) ;
+
+ /* Deal with knock on effect on real peer */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->state == bgp_peer_sEstablished)
- {
- /* Unless can dynamically reconfigure: once a session is established,
- * turning off an address family requires the session to be dropped
- * and restarted.
- */
- if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
- {
- peer->afc_adv[afi][safi] = 0;
- peer->afc_nego[afi][safi] = 0;
+ bool down = true ;
- if (peer_active_nego (peer))
- {
- bgp_capability_send (peer, afi, safi,
- CAPABILITY_CODE_MP,
- CAPABILITY_ACTION_UNSET);
- bgp_clear_route_normal(peer, afi, safi);
- peer->pcount[afi][safi] = 0;
- }
- else
- {
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- else
- {
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- else if ((peer->state == bgp_peer_sIdle) && !peer_active (peer))
+ if ( (peer->state == bgp_peer_pEstablished)
+ && CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV) )
{
- /* In sIdle, the BGP Engine may be trying to connect... if no address
- * family is now active, need now to shut down the session.
- */
- bgp_peer_disable(peer, NULL) ;
+ /* If can dynamically reconfigure can avoid restarting the session. */
+ peer->afc_adv[afi][safi] = 0;
+ peer->afc_nego[afi][safi] = 0;
+
+ if (peer_active_nego (peer))
+ {
+ bool completed ;
+ bgp_capability_send (peer, afi, safi, CAPABILITY_CODE_MP,
+ CAPABILITY_ACTION_UNSET);
+ completed = bgp_clear_routes(peer, afi, safi, false) ;
+ /* If clearing routes does not complete, what do we do ? */
+ passert(completed) ;
+ peer->pcount[afi][safi] = 0;
+
+ down = false ; /* don't need to down the peer */
+ } ;
} ;
- }
+
+ if (down)
+ bgp_peer_down(peer, PEER_DOWN_AF_DEACTIVATE) ;
+ } ;
+
return 0;
}
@@ -1038,7 +972,7 @@ peer_group_get (struct bgp *bgp, const char *name)
group->bgp = bgp;
group->name = strdup (name);
group->peer = list_new ();
- group->conf = peer_new (bgp);
+ group->conf = bgp_peer_new (bgp);
if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name);
@@ -1133,6 +1067,7 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
/* Import policy. */
if (pfilter->map[RMAP_IMPORT].name)
free (pfilter->map[RMAP_IMPORT].name);
+
if (gfilter->map[RMAP_IMPORT].name)
{
pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name);
@@ -1336,7 +1271,7 @@ peer_group_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
peer->group = NULL;
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
list_delete (group->peer);
@@ -1344,7 +1279,7 @@ peer_group_delete (struct peer_group *group)
group->name = NULL;
group->conf->group = NULL;
- peer_delete (group->conf);
+ bgp_peer_delete (group->conf);
/* Delete from all peer_group list. */
listnode_delete (bgp->group, group);
@@ -1366,7 +1301,7 @@ peer_group_remote_as_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
peer->group = NULL;
- peer_delete (peer);
+ bgp_peer_delete (peer);
}
list_delete_all_node (group->peer);
@@ -1381,7 +1316,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
struct peer_group *group, afi_t afi, safi_t safi, as_t *as)
{
struct peer *peer;
- int first_member = 0;
+ bool first_member ;
/* Check peer group's address family. */
if (! group->conf->afc[afi][safi])
@@ -1390,63 +1325,94 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
/* Lookup the peer. */
peer = peer_lookup (bgp, su);
- /* Create a new peer. */
+ /* Create a new peer -- iff group specifies a remote-as. */
if (! peer)
{
if (! group->conf->as)
return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
- peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
+ peer = bgp_peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
peer->group = group;
peer->af_group[afi][safi] = 1;
- peer = peer_lock (peer); /* group->peer list reference */
+ peer = bgp_peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
peer_group2peer_config_copy (group, peer, afi, safi);
- return 0;
+ return 0 ; /* Done */
}
- /* When the peer already belongs to peer group, check the consistency. */
+ assert(bgp == peer->bgp) ;
+
+ /* When the peer already belongs to peer group, check the consistency.
+ *
+ * If already belong to a group for the current afi/safi, then must be the
+ * same group -- cannot change group association by this means.
+ */
if (peer->af_group[afi][safi])
{
if (strcmp (peer->group->name, group->name) != 0)
return BGP_ERR_PEER_GROUP_CANT_CHANGE;
- return 0;
+ return 0; /* Done */
}
- /* Check current peer group configuration. */
+ /* Check current peer group configuration.
+ *
+ * Can only belong to one group at a time. All afi/safi which are members of
+ * a group, must be members of the same group.
+ */
if (peer_group_active (peer)
&& strcmp (peer->group->name, group->name) != 0)
return BGP_ERR_PEER_GROUP_MISMATCH;
- if (! group->conf->as)
- {
- if (peer_sort (group->conf) != BGP_PEER_INTERNAL
- && peer_sort (group->conf) != peer_sort (peer))
- {
- if (as)
- *as = peer->as;
- return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
- }
+ /* If binding to this group would change the sort of peer, then cannot
+ * do it.
+ *
+ * The group itself may not carry a sort of peer ?? Or something ??
+ */
+ first_member = false ;
+ if (! group->conf->as) /* If group does NOT specify a remote AS ? */
+ {
if (peer_sort (group->conf) == BGP_PEER_INTERNAL)
- first_member = 1;
+ first_member = true ;
+ else
+ {
+ if (peer_sort (group->conf) != peer_sort (peer))
+ {
+ if (as)
+ *as = peer->as;
+ return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+ }
+ }
}
+ /* Can join the group.
+ *
+ * NB: if we get to here, then we know that this afi/safi was NOT a member
+ * of any group.
+ *
+ * Note that this appears to implicitly activate the afi/safi... but does
+ * not go through the rest of the activation process ???
+ *
+ * TODO: why does implicit activation of afi/safi not do more work ?
+ */
peer->af_group[afi][safi] = 1;
peer->afc[afi][safi] = 1;
+
+ /* If not already a member, add to list of members. */
if (! peer->group)
{
peer->group = group;
- peer = peer_lock (peer); /* group->peer list reference */
+ peer = bgp_peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
}
else
assert (group && peer->group == group);
+ /* Further magic stuff to do with peer sort. */
if (first_member)
{
/* Advertisement-interval reset */
@@ -1467,48 +1433,39 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
}
}
+ /* Worry about rsclient state of the peer for this afi/safi.
+ *
+ * A peer cannot be an rsclient separately from its group.
+ *
+ * This peer was not previously a member of any group for this afi/safi.
+ *
+ * So if the peer is an rsclient for this afi/safi, it had better stop
+ * that now.
+ */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
{
- struct listnode *pn;
-
- /* If it's not configured as RSERVER_CLIENT in any other address
- family, without being member of a peer_group, remove it from
- list bgp->rsclient.*/
- if (! peer_rsclient_active (peer)
- && (pn = listnode_lookup (bgp->rsclient, peer)))
- {
- peer_unlock (peer); /* peer rsclient reference */
- list_delete_node (bgp->rsclient, pn);
+ /* Now that we have set peer->af_group for this afi/safi, this peer
+ * may no longer have any distinct rsclient status, in which case it
+ * must be removes from list bgp->rsclient.
+ *
+ * Note that it must have had distinct rsclient status, because it is
+ * an rsclient in this afi/safi, and it was not a group member in this
+ * afi/safi.
+ *
+ * We discard any import and export route map, except if the group is
+ * an rsclient, when we keep the export route map.
+ */
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ;
- /* Clear our own rsclient rib for this afi/safi. */
- bgp_clear_route_rsclient (peer, afi, safi);
- }
-
- bgp_table_finish (&peer->rib[afi][safi]);
-
- /* Import policy. */
- if (peer->filter[afi][safi].map[RMAP_IMPORT].name)
- {
- free (peer->filter[afi][safi].map[RMAP_IMPORT].name);
- peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL;
- peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL;
- }
-
- /* Export policy. */
- if (! CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
- && peer->filter[afi][safi].map[RMAP_EXPORT].name)
- {
- free (peer->filter[afi][safi].map[RMAP_EXPORT].name);
- peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL;
- peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL;
- }
+ peer_rsclient_unset(peer, afi, safi,
+ CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) ;
}
+ /* Now deal with the rest of the group configuration. */
peer_group2peer_config_copy (group, peer, afi, safi);
- peer->last_reset = PEER_DOWN_RMAP_BIND;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ /* And down the peer to push into new state. */
+ bgp_peer_down(peer, PEER_DOWN_RMAP_BIND) ;
return 0;
}
@@ -1518,35 +1475,42 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
struct peer_group *group, afi_t afi, safi_t safi)
{
if (! peer->af_group[afi][safi])
- return 0;
+ return 0; /* quit if not member of any group */
if (group != peer->group)
- return BGP_ERR_PEER_GROUP_MISMATCH;
+ return BGP_ERR_PEER_GROUP_MISMATCH; /* quit if not member of this group */
+ /* So is a member of this group for this afi/safi.
+ *
+ * This is an implied deactivation for this peer. That is taken care of in
+ * bgp_peer_down().
+ */
peer->af_group[afi][safi] = 0;
peer->afc[afi][safi] = 0;
peer_af_flag_reset (peer, afi, safi);
- if (peer->rib[afi][safi])
- peer->rib[afi][safi] = NULL;
+ /* Is member of group, so if it is an rsclient we were using its rsclient
+ * RIB, which must now forget.
+ */
+ peer->rib[afi][safi] = NULL;
+ /* If is now not a member of any group */
if (! peer_group_active (peer))
{
assert (listnode_lookup (group->peer, peer));
- peer_unlock (peer); /* peer group list reference */
+ bgp_peer_unlock (peer); /* peer group list reference */
listnode_delete (group->peer, peer);
peer->group = NULL;
if (group->conf->as)
{
- peer_delete (peer);
+ bgp_peer_delete (peer);
return 0;
}
peer_global_config_reset (peer);
}
- peer->last_reset = PEER_DOWN_RMAP_UNBIND;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_RMAP_UNBIND) ;
+
return 0;
}
@@ -1562,7 +1526,7 @@ bgp_create (as_t *as, const char *name)
return NULL;
bgp_lock (bgp);
- bgp->peer_self = peer_new (bgp);
+ bgp->peer_self = bgp_peer_new (bgp);
bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement");
bgp->peer = list_new ();
@@ -1710,7 +1674,7 @@ bgp_delete (struct bgp *bgp)
bgp_redistribute_unset (bgp, afi, i);
for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- peer_delete (peer);
+ bgp_peer_delete (peer);
for (ALL_LIST_ELEMENTS (bgp->group, node, next, group))
peer_group_delete (group);
@@ -1718,7 +1682,7 @@ bgp_delete (struct bgp *bgp)
assert (listcount (bgp->rsclient) == 0);
if (bgp->peer_self) {
- peer_delete(bgp->peer_self);
+ bgp_peer_delete(bgp->peer_self);
bgp->peer_self = NULL;
}
@@ -1783,8 +1747,7 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
if (bgp != NULL)
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (sockunion_same (&peer->su, su))
return peer;
}
else if (bm->bgp != NULL)
@@ -1793,13 +1756,13 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (sockunion_same (&peer->su, su))
return peer;
}
return NULL;
}
+#if 0
struct peer *
peer_lookup_with_open (union sockunion *su, as_t remote_as,
struct in_addr *remote_id, int *as)
@@ -1842,6 +1805,7 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
}
return NULL;
}
+#endif
/* If peer is configured at least one address family return 1. */
int
@@ -1869,200 +1833,222 @@ peer_active_nego (struct peer *peer)
return 0;
}
-/* peer_flag_change_type. */
+/*------------------------------------------------------------------------------
+ * Actions required after a change of state of a peer.
+ */
enum peer_change_type
{
- peer_change_none,
- peer_change_reset,
- peer_change_reset_in,
- peer_change_reset_out,
-};
-
+ peer_change_none, /* no further action */
+ peer_change_reset, /* drop any existing session and restart */
+ peer_change_reset_in, /* if possible, ask for route refresh,
+ otherwise drop and restart. */
+ peer_change_reset_out, /* reannounce everything */
+} ;
+
+typedef enum peer_change_type peer_change_type_t ;
+
+/* Perform action after change of state of a peer for the given afi/safi.
+ *
+ * If has to down the peer (drop any existing session and restart), then
+ * requires a peer_down_t to record why.
+ */
static void
peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
- enum peer_change_type type)
+ enum peer_change_type type,
+ peer_down_t why_changed)
{
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
return;
- if (type == peer_change_reset)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else if (type == peer_change_reset_in)
- {
- if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- else
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else if (type == peer_change_reset_out)
- bgp_announce_route (peer, afi, safi);
-}
+ switch (type)
+ {
+ case peer_change_none:
+ break ;
+ case peer_change_reset:
+ bgp_peer_down(peer, why_changed) ;
+ break ;
+
+ case peer_change_reset_in:
+ if (peer->state == bgp_peer_pEstablished)
+ {
+ if ( CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ else
+ bgp_peer_down(peer, why_changed);
+ } ;
+ break ;
+
+ case peer_change_reset_out:
+ bgp_announce_route (peer, afi, safi) ; /* Does nothing if !pEstablished */
+ break ;
+
+ default:
+ zabort("unknown peer_change_type") ;
+ break ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ *
+ *
+ */
struct peer_flag_action
{
- /* Peer's flag. */
+ /* Peer's flag. */
u_int32_t flag;
- /* This flag can be set for peer-group member. */
- u_char not_for_member;
+ /* This flag can be set for peer-group member. */
+ bool not_for_member;
- /* Action when the flag is changed. */
- enum peer_change_type type;
+ /* Action when the flag is changed. */
+ peer_change_type_t type;
- /* Peer down cause */
- u_char peer_down;
+ /* Peer down cause */
+ peer_down_t peer_down;
};
+/*------------------------------------------------------------------------------
+ * Table of actions for changing peer->flags
+ *
+ * NB: change actions are peer_change_none or peer_change_reset ONLY.
+ * (The peer->flags apply to all afi/safi.)
+ *
+ * NB: PEER_FLAG_LOCAL_AS_NO_PREPEND is dealt with eslewhere.
+ *
+ * NB: all flags are set/cleared individually.
+ */
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_DONT_CAPABILITY, 0, peer_change_none },
- { PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none },
- { PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none },
- { PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset },
- { PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset },
- { 0, 0, 0 }
+ { PEER_FLAG_PASSIVE,
+ false, peer_change_reset, PEER_DOWN_PASSIVE_CHANGE},
+ { PEER_FLAG_SHUTDOWN,
+ false, peer_change_reset, PEER_DOWN_USER_SHUTDOWN },
+ { PEER_FLAG_DONT_CAPABILITY,
+ false, peer_change_none, PEER_DOWN_NULL },
+ { PEER_FLAG_OVERRIDE_CAPABILITY,
+ false, peer_change_none, PEER_DOWN_NULL },
+ { PEER_FLAG_STRICT_CAP_MATCH,
+ false, peer_change_none, PEER_DOWN_NULL },
+ { PEER_FLAG_DYNAMIC_CAPABILITY,
+ false, peer_change_reset, PEER_DOWN_CAPABILITY_CHANGE },
+ { PEER_FLAG_DISABLE_CONNECTED_CHECK,
+ false, peer_change_reset, PEER_DOWN_CONFIG_CHANGE },
+ { 0, false, peer_change_none, PEER_DOWN_NULL }
};
+/*------------------------------------------------------------------------------
+ * Table of actions for changing peer->af_flags
+ *
+ * NB: some flags may be set/cleared together, in any combination.
+ */
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_SOFT_RECONFIG, 0, peer_change_reset_in },
- { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
- { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
- { PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out },
- { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in },
- { 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 },
- { 0, 0, 0 }
+ { PEER_FLAG_NEXTHOP_SELF,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_SEND_COMMUNITY
+ | PEER_FLAG_SEND_EXT_COMMUNITY,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_SOFT_RECONFIG,
+ false, peer_change_reset_in, PEER_DOWN_CONFIG_CHANGE },
+ { PEER_FLAG_REFLECTOR_CLIENT,
+ true, peer_change_reset, PEER_DOWN_RR_CLIENT_CHANGE },
+ { PEER_FLAG_RSERVER_CLIENT,
+ true, peer_change_reset, PEER_DOWN_RS_CLIENT_CHANGE },
+ { PEER_FLAG_AS_PATH_UNCHANGED
+ | PEER_FLAG_NEXTHOP_UNCHANGED
+ | PEER_FLAG_MED_UNCHANGED,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_REMOVE_PRIVATE_AS,
+ true, peer_change_reset_out, PEER_DOWN_NULL },
+ { PEER_FLAG_ALLOWAS_IN,
+ false, peer_change_reset_in, PEER_DOWN_ALLOWAS_IN_CHANGE },
+ { PEER_FLAG_ORF_PREFIX_SM
+ | PEER_FLAG_ORF_PREFIX_RM,
+ true, peer_change_reset, PEER_DOWN_CONFIG_CHANGE },
+ { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED,
+ false, peer_change_reset_out, PEER_DOWN_NULL },
+ { 0, false, peer_change_none, PEER_DOWN_NULL }
};
-/* Proper action set. */
-static int
-peer_flag_action_set (const struct peer_flag_action *action_list, int size,
- struct peer_flag_action *action, u_int32_t flag)
+/*------------------------------------------------------------------------------
+ * Look up action for given flags.
+ *
+ * Returns: address of required peer_flag_action structure,
+ * or: NULL if no action found for the given combination of flags.
+ *
+ * This mechanism is generally used when setting/clearing one flag at a time.
+ *
+ * The table may contain entries with more than one flag. In these cases,
+ * any combination of those flags may be set/cleared together -- any flags
+ * which are not mentioned are not affected.
+ *
+ * The given flags value must either exactly match a single flag entry, or be
+ * a subset of a multiple flag entry. The table is searched in the order
+ * given, and proceeds to the end before stopping.
+ */
+static const struct peer_flag_action*
+peer_flag_action_set (const struct peer_flag_action* action, uint32_t flag)
{
- int i;
- int found = 0;
- int reset_in = 0;
- int reset_out = 0;
- const struct peer_flag_action *match = NULL;
-
- /* Check peer's frag action. */
- for (i = 0; i < size; i++)
+ while (action->flag != 0)
{
- match = &action_list[i];
-
- if (match->flag == 0)
- break;
-
- if (match->flag & flag)
- {
- found = 1;
-
- if (match->type == peer_change_reset_in)
- reset_in = 1;
- if (match->type == peer_change_reset_out)
- reset_out = 1;
- if (match->type == peer_change_reset)
- {
- reset_in = 1;
- reset_out = 1;
- }
- if (match->not_for_member)
- action->not_for_member = 1;
- }
+ if ((action->flag & flag) == flag)
+ return action ;
+ action++ ;
}
- /* Set peer clear type. */
- if (reset_in && reset_out)
- action->type = peer_change_reset;
- else if (reset_in)
- action->type = peer_change_reset_in;
- else if (reset_out)
- action->type = peer_change_reset_out;
- else
- action->type = peer_change_none;
-
- return found;
+ return NULL ;
}
+/*------------------------------------------------------------------------------
+ * Having set or cleared something in peer->flags, make any implied changes.
+ *
+ * NB: Clearing PEER_FLAG_SHUTDOWN is a special case
+ *
+ * NB: Setting PEER_FLAG_SHUTDOWN -> PEER_DOWN_USER_SHUTDOWN, which is a
+ * special case in bgp_peer_down.
+ */
static void
-peer_flag_modify_action (struct peer *peer, u_int32_t flag)
+peer_flag_modify_action (struct peer *peer,
+ const struct peer_flag_action* action, bool set)
{
- if (flag == PEER_FLAG_SHUTDOWN)
- {
- if (CHECK_FLAG (peer->flags, flag))
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
+ if (action->type == peer_change_none)
+ return ;
- UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart)
- {
- BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s Maximum-prefix restart timer cancelled",
- peer->host);
- }
-#if 0 /* TODO: surely no need to peer_nsf_stop() twice ? */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
-#endif
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
- else
- {
- peer->v_start = BGP_INIT_START_TIMER;
- bgp_peer_enable(peer);
- }
- }
- else
+ assert(action->type == peer_change_reset) ;
+
+ if ((action->flag == PEER_FLAG_SHUTDOWN) && !set)
{
- if (flag == PEER_FLAG_DYNAMIC_CAPABILITY)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_PASSIVE)
- peer->last_reset = PEER_DOWN_PASSIVE_CHANGE;
- else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)
- peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE;
+ peer->v_start = BGP_INIT_START_TIMER;
+ bgp_peer_enable(peer);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
-}
+ return ; /* Note */
+ } ;
-/* Change specified peer flag. */
+ bgp_peer_down(peer, action->peer_down) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Change specified peer->flags flag.
+ *
+ * See: peer_flag_action_list above.
+ */
static int
-peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
+peer_flag_modify (struct peer *peer, u_int32_t flag, bool set)
{
- int found;
- int size;
struct peer_group *group;
struct listnode *node, *nnode;
- struct peer_flag_action action;
+ const struct peer_flag_action* action;
- memset (&action, 0, sizeof (struct peer_flag_action));
- size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action);
-
- found = peer_flag_action_set (peer_flag_action_list, size, &action, flag);
+ action = peer_flag_action_set (peer_flag_action_list, flag) ;
/* No flag action is found. */
- if (! found)
+ if (action == NULL)
return BGP_ERR_INVALID_FLAG;
/* Not for peer-group member. */
- if (action.not_for_member && peer_group_active (peer))
+ if (action->not_for_member && peer_group_active (peer))
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
/* When unset the peer-group member's flag we have to check
@@ -2097,9 +2083,7 @@ peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (action.type == peer_change_reset)
- peer_flag_modify_action (peer, flag);
-
+ peer_flag_modify_action (peer, action, set);
return 0;
}
@@ -2119,22 +2103,27 @@ peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
else
UNSET_FLAG (peer->flags, flag);
- if (action.type == peer_change_reset)
- peer_flag_modify_action (peer, flag);
+ peer_flag_modify_action (peer, action, set);
}
return 0;
}
+/*------------------------------------------------------------------------------
+ * Set specified peer->flags flag.
+ */
int
peer_flag_set (struct peer *peer, u_int32_t flag)
{
- return peer_flag_modify (peer, flag, 1);
+ return peer_flag_modify (peer, flag, true);
}
+/*------------------------------------------------------------------------------
+ * Clear specified peer->flags flag.
+ */
int
peer_flag_unset (struct peer *peer, u_int32_t flag)
{
- return peer_flag_modify (peer, flag, 0);
+ return peer_flag_modify (peer, flag, false);
}
static int
@@ -2145,23 +2134,43 @@ peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi)
return 0;
}
-static int
+/*------------------------------------------------------------------------------
+ * Having set or cleared something in peer->af_flags, make any implied changes.
+ *
+ * NB: clearing PEER_FLAG_SOFT_RECONFIG is a special case.
+ */
+static void
+peer_af_flag_modify_action (struct peer *peer, afi_t afi, safi_t safi,
+ const struct peer_flag_action* action, bool set)
+{
+ if ((action->flag == PEER_FLAG_SOFT_RECONFIG) && !set)
+ {
+ if (peer->state == bgp_peer_pEstablished)
+ bgp_clear_adj_in (peer, afi, safi);
+ }
+ else
+ {
+ peer_change_action (peer, afi, safi, action->type, action->peer_down) ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Change specified peer->af_flags flag.
+ *
+ * See: peer_af_flag_action_list above.
+ */
+int
peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
- int set)
+ bool set)
{
- int found;
- int size;
struct listnode *node, *nnode;
struct peer_group *group;
- struct peer_flag_action action;
-
- memset (&action, 0, sizeof (struct peer_flag_action));
- size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action);
+ const struct peer_flag_action* action;
- found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag);
+ action = peer_flag_action_set (peer_af_flag_action_list, flag);
/* No flag action is found. */
- if (! found)
+ if (action == NULL)
return BGP_ERR_INVALID_FLAG;
/* Adress family must be activated. */
@@ -2169,17 +2178,16 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
return BGP_ERR_PEER_INACTIVE;
/* Not for peer-group member. */
- if (action.not_for_member && peer_is_group_member (peer, afi, safi))
+ if (action->not_for_member && peer_is_group_member (peer, afi, safi))
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
/* Spcecial check for reflector client. */
- if (flag & PEER_FLAG_REFLECTOR_CLIENT
- && peer_sort (peer) != BGP_PEER_IBGP)
+ if ((flag & PEER_FLAG_REFLECTOR_CLIENT) && (peer_sort(peer) != BGP_PEER_IBGP))
return BGP_ERR_NOT_INTERNAL_PEER;
/* Spcecial check for remove-private-AS. */
- if (flag & PEER_FLAG_REMOVE_PRIVATE_AS
- && peer_sort (peer) == BGP_PEER_IBGP)
+ if ((flag & PEER_FLAG_REMOVE_PRIVATE_AS)
+ && (peer_sort(peer) == BGP_PEER_IBGP))
return BGP_ERR_REMOVE_PRIVATE_AS;
/* When unset the peer-group member's flag we have to check
@@ -2191,7 +2199,7 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
/* When current flag configuration is same as requested one. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+ if ( set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
return 0;
if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
return 0;
@@ -2202,82 +2210,54 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
else
UNSET_FLAG (peer->af_flags[afi][safi], flag);
- /* Execute action when peer is established. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && peer->state == bgp_peer_sEstablished)
+ /* Execute action. */
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in (peer, afi, safi);
- else
- {
- if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_RSERVER_CLIENT)
- peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_SM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_RM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
-
- peer_change_action (peer, afi, safi, action.type);
- }
-
- }
+ peer_af_flag_modify_action(peer, afi, safi, action, set) ;
+ return 0 ;
+ } ;
/* Peer group member updates. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
- group = peer->group;
+ if (! peer->af_group[afi][safi])
+ continue;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (! peer->af_group[afi][safi])
- continue;
+ if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+ continue;
- if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
- continue;
+ if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
+ continue;
- if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
- continue;
+ if (set)
+ SET_FLAG (peer->af_flags[afi][safi], flag);
+ else
+ UNSET_FLAG (peer->af_flags[afi][safi], flag);
- if (set)
- SET_FLAG (peer->af_flags[afi][safi], flag);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], flag);
+ peer_af_flag_modify_action(peer, afi, safi, action, set) ;
+ } ;
- if (peer->state == bgp_peer_sEstablished)
- {
- if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in (peer, afi, safi);
- else
- {
- if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_RSERVER_CLIENT)
- peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_SM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_RM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
-
- peer_change_action (peer, afi, safi, action.type);
- }
- }
- }
- }
return 0;
}
+/*------------------------------------------------------------------------------
+ * Set specified peer->af_flags flag.
+ */
int
peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
{
- return peer_af_flag_modify (peer, afi, safi, flag, 1);
+ return peer_af_flag_modify (peer, afi, safi, flag, true);
}
+/*------------------------------------------------------------------------------
+ * Clear specified peer->af_flags flag.
+ */
int
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);
+ return peer_af_flag_modify (peer, afi, safi, flag, false);
}
/* EBGP multihop configuration. */
@@ -2405,9 +2385,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
return 0;
}
@@ -2432,9 +2410,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname);
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
}
return 0;
}
@@ -2464,9 +2440,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
return 0;
}
@@ -2490,9 +2464,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
peer->update_source = sockunion_dup (su);
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
}
return 0;
}
@@ -2536,9 +2508,7 @@ peer_update_source_unset (struct peer *peer)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
return 0;
}
@@ -2561,9 +2531,7 @@ peer_update_source_unset (struct peer *peer)
peer->update_if = NULL;
}
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_UPDATE_SOURCE_CHANGE) ;
}
return 0;
}
@@ -2600,7 +2568,7 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 0);
return 0;
}
@@ -2619,7 +2587,7 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
}
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 0);
}
return 0;
@@ -2651,7 +2619,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 1);
return 0;
}
@@ -2667,7 +2635,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
- if (peer->state == bgp_peer_sEstablished && peer->afc_nego[afi][safi])
+ if (peer->state == bgp_peer_pEstablished && peer->afc_nego[afi][safi])
bgp_default_originate (peer, afi, safi, 1);
}
return 0;
@@ -2908,7 +2876,8 @@ peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
{
peer->allowas_in[afi][safi] = allow_num;
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
- peer_change_action (peer, afi, safi, peer_change_reset_in);
+ peer_change_action (peer, afi, safi, peer_change_reset_in,
+ PEER_DOWN_ALLOWAS_IN_CHANGE) ;
}
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
@@ -2921,7 +2890,8 @@ peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
{
peer->allowas_in[afi][safi] = allow_num;
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
- peer_change_action (peer, afi, safi, peer_change_reset_in);
+ peer_change_action (peer, afi, safi, peer_change_reset_in,
+ PEER_DOWN_ALLOWAS_IN_CHANGE) ;
}
}
@@ -2985,10 +2955,8 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- return 0;
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
+ return 0 ;
}
group = peer->group;
@@ -3000,9 +2968,7 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
else
UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
}
return 0;
@@ -3025,9 +2991,7 @@ peer_local_as_unset (struct peer *peer)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
return 0;
}
@@ -3037,9 +3001,7 @@ peer_local_as_unset (struct peer *peer)
peer->change_local_as = 0;
UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_LOCAL_AS_CHANGE) ;
}
return 0;
}
@@ -3066,8 +3028,7 @@ peer_password_set (struct peer *peer, const char *password)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
return BGP_SUCCESS;
}
@@ -3081,8 +3042,7 @@ peer_password_set (struct peer *peer, const char *password)
peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
}
return ret;
@@ -3104,13 +3064,14 @@ peer_password_unset (struct peer *peer)
&& strcmp (peer->group->conf->password, peer->password) == 0)
return BGP_ERR_PEER_GROUP_HAS_THE_FLAG;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
-
if (peer->password)
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
+ {
+ XFREE (MTYPE_PEER_PASSWORD, peer->password);
+ /* sets peer->password NULL */
+
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
+ } ;
- peer->password = NULL;
return 0;
}
@@ -3122,11 +3083,9 @@ peer_password_unset (struct peer *peer)
if (!peer->password)
continue;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
-
XFREE (MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
+ /* sets peer->password NULL */
+ bgp_peer_down(peer, PEER_DOWN_PASSWORD_CHANGE) ;
}
return 0;
@@ -3840,30 +3799,14 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi)
int
peer_clear (struct peer *peer)
{
- if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
- {
- UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart)
- {
- BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s Maximum-prefix restart timer cancelled",
- peer->host);
- }
+ /* Overrides any Max Prefix issues. */
+ bgp_maximum_prefix_cancel_timer (peer) ;
- /* Beware we may still be clearing, if so the end of
- * clearing will enable the peer */
- bgp_peer_enable(peer);
+ /* Overrides any idle hold timer */
+ peer->v_start = BGP_INIT_START_TIMER;
- return 0;
- }
+ bgp_peer_down(peer, PEER_DOWN_USER_RESET) ;
- peer->v_start = BGP_INIT_START_TIMER;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_RESET);
- }
return 0;
}
@@ -3871,7 +3814,7 @@ int
peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
enum bgp_clear_type stype)
{
- if (peer->state == bgp_peer_sEstablished)
+ if (peer->state == bgp_peer_pEstablished)
return 0;
if (! peer->afc[afi][safi])
@@ -3922,7 +3865,8 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
}
}
- if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH
+ if ( stype == BGP_CLEAR_SOFT_IN
+ || stype == BGP_CLEAR_SOFT_BOTH
|| stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX)
{
/* If neighbor has soft reconfiguration inbound flag.
@@ -4446,11 +4390,8 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
{
if (peer->afc[afi][safi])
{
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- bgp_config_write_family_header (vty, afi, safi, &write);
- bgp_config_write_peer (vty, bgp, peer, afi, safi);
- }
+ bgp_config_write_family_header (vty, afi, safi, &write);
+ bgp_config_write_peer (vty, bgp, peer, afi, safi);
}
}
if (write)
@@ -4621,10 +4562,7 @@ bgp_config_write (struct vty *vty)
/* Normal neighbor configuration. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
- }
+ bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
/* Distance configuration. */
bgp_config_write_distance (vty, bgp);
@@ -4657,11 +4595,18 @@ bgp_master_init (void)
bm = &bgp_master;
bm->bgp = list_new ();
- bm->port = BGP_PORT_DEFAULT;
bm->master = thread_master_create ();
+ bm->port = BGP_PORT_DEFAULT;
bm->start_time = time (NULL);
-}
+ /* Implicitly:
+ *
+ * address = NULL -- no special listen address
+ * options = 0 -- no options set
+ * as2_speaker = false -- as4 speaker by default
+ * peer_linger_count = 0 -- no peers lingering
+ */
+} ;
void
bgp_init (void)
@@ -4707,6 +4652,12 @@ bgp_init (void)
#endif /* HAVE_SNMP */
}
+/*------------------------------------------------------------------------------
+ * If not terminating, reset all peers now
+ *
+ * If
+ *
+ */
void
bgp_terminate (int terminating, int retain_mode)
{
@@ -4715,75 +4666,22 @@ bgp_terminate (int terminating, int retain_mode)
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
- program_terminating = terminating;
-
- /* Disable all peers */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (retain_mode)
- bgp_peer_disable(peer, NULL);
- else if (terminating)
- {
- peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
- /* Belt and braces, probably redundant */
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
- else
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_RESET);
- }
-
- if (!retain_mode)
- bgp_cleanup_routes ();
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ /* If we are retaining, then turn off changes to the FIB. */
+ if (retain_mode)
{
- if (bgp->process_main_queue)
- {
- work_queue_free (bgp->process_main_queue);
- bgp->process_main_queue = NULL;
- }
- if (bgp->process_rsclient_queue)
- {
- work_queue_free (bgp->process_rsclient_queue);
- bgp->process_rsclient_queue = NULL;
- }
- }
-
- /* if no sessions were enabled then need to check here */
- program_terminate_if_all_disabled();
-}
+ assert(terminating) ; /* Can only retain when terminating */
+ bgp_option_set(BGP_OPT_NO_FIB) ;
+ } ;
-/* If we are terminating the program, and all sessions are disabled
- * then terminate all threads
- */
-void
-program_terminate_if_all_disabled(void)
-{
- struct bgp *bgp;
- struct peer *peer;
- struct listnode *node, *nnode;
- struct listnode *mnode, *mnnode;
-
- if (!program_terminating)
- return;
-
- /* are there any active sessions remaining? */
+ /* For all bgp instances... */
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (bgp_session_is_active(peer->session))
- return;
-
- /* ask remaining pthreads to die */
- if (qpthreads_enabled && routing_nexus != NULL)
- qpn_terminate(routing_nexus);
-
- if (qpthreads_enabled && bgp_nexus != NULL)
- qpn_terminate(bgp_nexus);
-
- if (cli_nexus != NULL)
- qpn_terminate(cli_nexus);
-}
+ {
+ /* ...delete or down all peers. */
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (terminating)
+ bgp_peer_delete(peer) ;
+ else
+ bgp_peer_down(peer, PEER_DOWN_USER_RESET) ;
+ } ;
+} ;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index cd92576a..7a53c511 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -35,19 +35,17 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* BGP master for system wide configurations and variables. */
struct bgp_master
{
- /* BGP instance list. */
+ /* BGP instance list. */
struct list *bgp;
- /* BGP thread master. */
+ /* BGP thread master. */
struct thread_master *master;
- /* BGP port number. */
- u_int16_t port;
-
- /* Listener address */
+ /* Listener address & port number */
char *address;
+ u_int16_t port;
- /* BGP start time. */
+ /* BGP start time. */
time_t start_time;
/* Various BGP global configuration. */
@@ -58,6 +56,9 @@ struct bgp_master
/* Do not announce AS4 */
bool as2_speaker ;
+
+ /* Peers lingering in pDeleting */
+ unsigned peer_linger_count ;
};
/* BGP instance structure. */
@@ -69,7 +70,7 @@ struct bgp
/* Name of this BGP instance. */
char *name;
- /* Reference count to allow peer_delete to finish after bgp_delete */
+ /* Reference count to allow bgp_peer_delete to finish after bgp_delete */
int lock;
/* Self peer. */
@@ -423,8 +424,6 @@ 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 *);
extern int peer_sort (struct peer *peer);
extern int peer_active (struct peer *);
extern int peer_active_nego (struct peer *);
@@ -474,13 +473,15 @@ 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_delete (struct peer *peer);
extern int peer_group_delete (struct peer_group *);
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 void peer_rsclient_unset(struct peer* peer, int afi, int safi,
+ bool keep_export) ;
+
extern int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *,
afi_t, safi_t, as_t *);
extern int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *,
@@ -491,6 +492,8 @@ extern int peer_flag_unset (struct peer *, u_int32_t);
extern int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t);
extern int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t);
+extern int peer_af_flag_modify (struct peer *, afi_t, safi_t, u_int32_t,
+ bool set) ;
extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t);
extern int peer_ebgp_multihop_set (struct peer *, int);
diff --git a/configure.ac b/configure.ac
index 85784080..3507a120 100755
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@
## $Id$
AC_PREREQ(2.53)
-AC_INIT(Quagga, 0.99.15ex01, [http://bugzilla.quagga.net])
+AC_INIT(Quagga, 0.99.15ex02, [http://bugzilla.quagga.net])
AC_CONFIG_SRCDIR(lib/zebra.h)
AC_CONFIG_MACRO_DIR([m4])
diff --git a/lib/plist.c b/lib/plist.c
index 41868e96..85ff35f8 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -700,18 +700,24 @@ prefix_list_entry_lookup_seq(struct prefix_list *plist, int seq, int* result)
*
* Returns index of an entry in the prefix_list or the dup_cache, and sets:
*
- * cache -- NULL if not using dup_cache for this prefix_list.
- * The index and result values refer to the main prefix_list.
+ * cache -- NULL if not using dup_cache for this prefix_list.
+ * The index and result values refer to the main prefix_list.
*
- * -- address of the cache (a vector).
- * The index and result values refer to the cache. << NB
+ * result < 0 -- not found. prefix list is empty, index == 0
+ * result == 0 -- found. index is of the prefix list entry
+ * result > 0 -- not found. prefix is not empty, index == last
*
- * result < 0 -- not found. index returned is of first entry in the
- * prefix list, and this sequence number comes
- * before it. (Or list is empty.)
- * result == 0 -- found. index is of the entry found.
- * result > 0 -- not found. index returned is of the entry with the largest
- * sequence number smaller than the given one.
+ * -- address of the cache (a vector).
+ * The index and result values refer to the *cache*. << NB
+ *
+ * result < 0 -- not found. index == 0, prefix value given is
+ * less than first entry in the *cache*
+ * result == 0 -- found. index is of the *cache* entry
+ * result > 0 -- not found. index is of entry in the *cache*
+ * with the largest prefix value less
+ * than the given prefix value.
+ *
+ * Note that the cache is never empty.
*/
static vector_index
prefix_list_entry_lookup_val(struct prefix_list *plist,
@@ -749,7 +755,9 @@ prefix_list_entry_lookup_val(struct prefix_list *plist,
if (plist->cmp(&pe, &temp) == 0)
return i ; /* Found ! */
} ;
- *result = 1 ; /* Not found. */
+
+ *result = (vector_end(&plist->list) == 0) ? -1 : +1 ;
+ /* Not found. */
return i ;
} ;
} ;
@@ -855,16 +863,21 @@ prefix_list_entry_insert(struct prefix_list *plist,
i = prefix_list_entry_lookup_seq(plist, temp->seq, &ret) ;
else
{
- int last_seq = 0 ;
+ int last_seq ;
i = vector_end(&plist->list) ;
- if (i != 0)
+ if (i == 0)
+ {
+ last_seq = 0 ; /* initial value for empty list */
+ ret = -1 ; /* insert before first item of empty list */
+ }
+ else
{
- --i ; /* step back to last entry */
+ --i ; /* step back to last entry */
pe = vector_get_item(&plist->list, i) ;
- last_seq = pe->seq ;
+ last_seq = pe->seq ;
+ ret = 1 ; /* insert after last entry */
} ;
temp->seq = (((last_seq + 5 - 1) / 5) * 5) + 5 ;
- ret = 1 ; /* insert after last entry (if any) */
} ;
/* If we found it with same sequence number, then replace entry,
diff --git a/lib/qpnexus.c b/lib/qpnexus.c
index 59dcc535..3b014be2 100644
--- a/lib/qpnexus.c
+++ b/lib/qpnexus.c
@@ -53,7 +53,7 @@ static void qpn_in_thread_init(qpn_nexus qpn);
* Returns the qpn_nexus.
*/
extern qpn_nexus
-qpn_init_new(qpn_nexus qpn, int main_thread)
+qpn_init_new(qpn_nexus qpn, bool main_thread)
{
if (qpn == NULL)
qpn = XCALLOC(MTYPE_QPN_NEXUS, sizeof(struct qpn_nexus)) ;
@@ -309,13 +309,19 @@ qpn_in_thread_init(qpn_nexus qpn)
}
/*------------------------------------------------------------------------------
- * Ask the thread to terminate itself quickly and cleanly
+ * Ask the thread to terminate itself quickly and cleanly.
+ *
+ * Does nothing if terminate already set.
*/
void
qpn_terminate(qpn_nexus qpn)
{
- qpn->terminate = 1;
- /* wake up any pselect */
- if (qpthreads_enabled)
- qpt_thread_signal(qpn->thread_id, SIGMQUEUE);
+ if (!qpn->terminate)
+ {
+ qpn->terminate = true ;
+
+ /* wake up any pselect */
+ if (qpthreads_enabled)
+ qpt_thread_signal(qpn->thread_id, SIGMQUEUE);
+ } ;
}
diff --git a/lib/qpnexus.h b/lib/qpnexus.h
index f4195a4d..0cf5a824 100644
--- a/lib/qpnexus.h
+++ b/lib/qpnexus.h
@@ -75,10 +75,10 @@ typedef struct qpn_nexus* qpn_nexus ;
struct qpn_nexus
{
/* set true to terminate the thread (eventually) */
- int terminate;
+ bool terminate;
/* true if this is the main thread */
- int main_thread;
+ bool main_thread;
/* thread ID */
qpt_thread_t thread_id;
@@ -146,7 +146,7 @@ struct qpn_nexus
* Functions
*/
-extern qpn_nexus qpn_init_new(qpn_nexus qpn, int main_thread);
+extern qpn_nexus qpn_init_new(qpn_nexus qpn, bool main_thread);
extern void qpn_add_hook_function(qpn_hook_list list, void* hook) ;
extern void qpn_exec(qpn_nexus qpn);
extern void qpn_terminate(qpn_nexus qpn);
diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c
index 8f265870..cae9a12d 100644
--- a/tests/bgp_capability_test.c
+++ b/tests/bgp_capability_test.c
@@ -664,7 +664,7 @@ main (void)
parse_test (peer, &opt_params[i++], OPT_PARAM);
SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
- peer->state = bgp_peer_sEstablished;
+ peer->state = bgp_peer_pEstablished;
i = 0;
while (dynamic_cap_msgs[i].name)