summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_main.c25
-rw-r--r--bgpd/bgp_open_state.c141
-rw-r--r--bgpd/bgp_open_state.h5
-rw-r--r--bgpd/bgp_peer.c384
-rw-r--r--bgpd/bgp_peer.h13
-rw-r--r--bgpd/bgpd.c293
-rw-r--r--bgpd/bgpd.h1
-rw-r--r--lib/command_queue.c53
-rw-r--r--lib/qpnexus.c150
-rw-r--r--lib/qpnexus.h1
10 files changed, 656 insertions, 410 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index c1ac1ae2..003b9df0 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -115,6 +115,7 @@ static int retain_mode = 0;
struct thread_master *master;
qpn_nexus cli_nexus = NULL;
qpn_nexus bgp_nexus = NULL;
+qpn_nexus routing_nexus = NULL;
/* Manually specified configuration file name. */
char *config_file = NULL;
@@ -209,17 +210,20 @@ sigint (void)
#endif
zlog_notice ("Terminating on signal");
- if (! retain_mode)
+ if (!retain_mode)
bgp_terminate ();
if (qpthreads_enabled)
{
/* ask all threads to terminate */
- if (bgp_nexus)
- qpn_terminate(bgp_nexus);
+ if (routing_nexus != NULL)
+ qpn_terminate(routing_nexus);
- if (cli_nexus)
- qpn_terminate(cli_nexus);
+ if (bgp_nexus != NULL)
+ qpn_terminate(bgp_nexus);
+
+ if (cli_nexus != NULL)
+ qpn_terminate(cli_nexus);
}
else
{
@@ -336,6 +340,7 @@ bgp_exit (int status)
if (CONF_BGP_DEBUG (normal, NORMAL))
log_memstats_stderr ("bgpd");
+ routing_nexus = qpn_free(routing_nexus);
bgp_nexus = qpn_free(bgp_nexus);
cli_nexus = qpn_free(cli_nexus);
@@ -476,6 +481,11 @@ main (int argc, char **argv)
if(dryrun)
return(0);
+ /* only the calling thread survives in the child after a fork
+ * so ensure we haven't created any threads yet
+ */
+ assert(!qpthreads_thread_created);
+
/* Turn into daemon if daemon_mode is set. */
if (daemon_mode && daemon (0, 0) < 0)
{
@@ -494,6 +504,7 @@ main (int argc, char **argv)
{
cli_nexus = qpn_init_main(cli_nexus); /* main thread */
bgp_nexus = qpn_init_bgp(bgp_nexus);
+ routing_nexus = qpn_init_bgp(routing_nexus);
vty_init_r(cli_nexus, bgp_nexus);
}
@@ -516,10 +527,14 @@ main (int argc, char **argv)
{
void * thread_result = NULL;
+ /* TODO: exec routing_nexus */
+ /* qpn_exec(routing_nexus); */
qpn_exec(bgp_nexus);
qpn_exec(cli_nexus); /* must be last to start - on main thread */
/* terminating, wait for all threads to finish */
+ /* TOD: join with routing_nexus */
+ /* thread_result = qpt_thread_join(routing_nexus->thread_id); */
thread_result = qpt_thread_join(bgp_nexus->thread_id);
bgp_exit(0);
}
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
index 76c4b4bd..5603364b 100644
--- a/bgpd/bgp_open_state.c
+++ b/bgpd/bgp_open_state.c
@@ -38,7 +38,7 @@
/* Initialise new bgp_open_state structure -- allocate if required.
*
*/
-extern bgp_open_state
+bgp_open_state
bgp_open_state_init_new(bgp_open_state state)
{
if (state == NULL)
@@ -47,15 +47,15 @@ bgp_open_state_init_new(bgp_open_state state)
memset(state, 0, sizeof(struct bgp_open_state)) ;
return state ;
-} ;
+}
-extern bgp_open_state
+bgp_open_state
bgp_open_state_free(bgp_open_state state)
{
if (state != NULL)
XFREE(MTYPE_BGP_OPEN_STATE, state) ;
return NULL ;
-} ;
+}
/*==============================================================================
* Construct new bgp_open_state for the given peer -- allocate if required.
@@ -63,7 +63,7 @@ bgp_open_state_free(bgp_open_state state)
* Initialises the structure according to the current peer state.
*/
-extern bgp_session
+bgp_open_state
bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
{
safi_t safi ;
@@ -87,6 +87,9 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
/* Set our bgpd_id */
state->bgp_id = peer->local_id ;
+ /* TODO: can_capability? */
+ state->can_capability = 0;
+
/* Announce self as AS4 speaker if required */
state->can_as4 = ((peer->cap & PEER_CAP_AS4_ADV) != 0) ;
@@ -95,7 +98,7 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
for (afi = qAFI_MIN ; afi <= qAFI_MAX ; ++afi)
for (safi = qSAFI_MIN ; safi <= qSAFI_MAX ; ++safi)
if (peer->afc[afi][safi])
- state->can_mp_ext |= quafi_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
+ state->can_mp_ext |= qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
/* Route refresh. */
state->can_r_refresh = (peer->cap & PEER_CAP_REFRESH_ADV)
@@ -108,10 +111,10 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
{
if (peer->af_flags[afi][safi] & PEER_FLAG_ORF_PREFIX_SM)
state->can_orf_prefix_send |=
- quafi_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
+ qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
if (peer->af_flags[afi][safi] & PEER_FLAG_ORF_PREFIX_RM)
state->can_orf_prefix_recv |=
- quafi_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
+ qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
} ;
state->can_orf_prefix = (state->can_orf_prefix_send |
@@ -135,4 +138,124 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
/* TODO: check not restarting and not preserving forwarding state (?) */
state->can_nsf = 0 ;
state->restarting = 0 ;
-} ;
+
+ return state;
+}
+
+/* Received an open, update the peer's state */
+void
+bgp_peer_open_state_receive(bgp_peer peer)
+{
+ bgp_session session = peer->session;
+ bgp_open_state open_send = session->open_send;
+ bgp_open_state open_rcvd = session->open_rcvd;
+ int afi;
+ int safi;
+
+ /* Check neighbor as number. */
+ assert(open_rcvd->my_as == peer->as);
+
+ /* holdtime */
+ /* From the rfc: A reasonable maximum time between KEEPALIVE messages
+ would be one third of the Hold Time interval. KEEPALIVE messages
+ MUST NOT be sent more frequently than one per second. An
+ implementation MAY adjust the rate at which it sends KEEPALIVE
+ messages as a function of the Hold Time interval. */
+
+ peer->v_holdtime =
+ (open_rcvd->holdtime < open_send->holdtime)
+ ? open_rcvd->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 ;
+
+ /* Set remote router-id */
+ peer->remote_id = open_rcvd->bgp_id;
+
+ /* AS4 */
+ if (open_rcvd->can_as4)
+ SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
+
+ /* AFI/SAFI */
+ /* Ignore capability when override-capability is set. */
+ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ {
+ for (afi = qAFI_MIN ; afi <= qAFI_MAX ; ++afi)
+ for (safi = qSAFI_MIN ; safi <= qSAFI_MAX ; ++safi)
+ {
+ qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
+ if (qb & open_rcvd->can_mp_ext)
+ {
+ peer->afc_recv[afi][safi] = 1;
+ assert(peer->afc[afi][safi]);
+ peer->afc_nego[afi][safi] = 1;
+ }
+ }
+ }
+
+ /* Route refresh. */
+ if (open_rcvd->can_r_refresh & bgp_cap_form_old)
+ SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+ else if (open_rcvd->can_r_refresh & bgp_cap_form_new)
+ SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+
+ /* ORF */
+ for (afi = qAFI_MIN ; afi <= qAFI_MAX ; ++afi)
+ for (safi = qSAFI_MIN ; safi <= qSAFI_MAX ; ++safi)
+ {
+ qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
+ if (qb & open_rcvd->can_orf_prefix_send)
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV);
+ if (qb & open_rcvd->can_orf_prefix_recv)
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV);
+ }
+
+ /* ORF prefix. */
+ if (open_rcvd->can_orf_prefix_send)
+ {
+ if (open_rcvd->can_orf_prefix & bgp_cap_form_old)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_SM_OLD_RCV);
+ else if (open_rcvd->can_orf_prefix & bgp_cap_form_new)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_SM_RCV);
+ }
+ if (open_rcvd->can_orf_prefix_recv)
+ {
+ if (open_rcvd->can_orf_prefix & bgp_cap_form_old)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_RM_OLD_RCV);
+ else if (open_rcvd->can_orf_prefix & bgp_cap_form_new)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_RM_RCV);
+ }
+
+ /* Graceful restart */
+ for (afi = qAFI_MIN ; afi <= qAFI_MAX ; ++afi)
+ for (safi = qSAFI_MIN ; safi <= qSAFI_MAX ; ++safi)
+ {
+ qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi));
+ if (peer->afc[afi][safi] && (qb & open_rcvd->can_g_restart))
+ {
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
+ if (qb & open_rcvd->can_nfs)
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
+ }
+ }
+
+ peer->v_gr_restart = open_rcvd->restart_time;
+ /* TODO: should we do anything with this? */
+#if 0
+ int restarting ; /* Restart State flag */
+#endif
+
+ /* Override capability. */
+ if (!open_rcvd->can_capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ {
+ peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST];
+ peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST];
+ peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST];
+ peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
+ }
+
+}
diff --git a/bgpd/bgp_open_state.h b/bgpd/bgp_open_state.h
index 6715f416..534dcadf 100644
--- a/bgpd/bgp_open_state.h
+++ b/bgpd/bgp_open_state.h
@@ -87,5 +87,10 @@ bgp_open_state_init_new(bgp_open_state state) ;
extern bgp_open_state
bgp_open_state_free(bgp_open_state state) ;
+extern bgp_open_state
+bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer);
+
+extern void
+bgp_peer_open_state_receive(bgp_peer peer);
#endif /* QUAGGA_BGP_OPEN_STATE_H */
diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c
index 03439928..3d686171 100644
--- a/bgpd/bgp_peer.c
+++ b/bgpd/bgp_peer.c
@@ -123,7 +123,7 @@ inline static void BGP_PEER_INDEX_UNLOCK(void)
*
* This must be done before any peers are configured !
*/
-extern void
+void
bgp_peer_index_init(void* parent)
{
symbol_table_init_new(
@@ -133,18 +133,18 @@ bgp_peer_index_init(void* parent)
200, /* allow to be quite dense */
sockunion_symbol_hash, /* "name" is an IP Address */
NULL) ; /* no value change call-back */
-} ;
+}
/*------------------------------------------------------------------------------
* Initialise the bgp_peer_index_mutex.
*
* This must be done before the BGP Engine is started.
*/
-extern void
+void
bgp_peer_index_mutex_init(void* parent)
{
qpt_mutex_init(&bgp_peer_index_mutex, qpt_mutex_recursive) ;
-} ;
+}
/*------------------------------------------------------------------------------
* Lookup a peer -- do nothing if does not exist
@@ -153,7 +153,7 @@ bgp_peer_index_mutex_init(void* parent)
*
* Returns the bgp_peer -- NULL if not found.
*/
-extern bgp_peer
+bgp_peer
bgp_peer_index_seek(union sockunion* su)
{
bgp_peer peer ;
@@ -165,7 +165,7 @@ bgp_peer_index_seek(union sockunion* su)
BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
return peer ;
-} ;
+}
/*------------------------------------------------------------------------------
* Register a peer in the peer index.
@@ -175,7 +175,7 @@ bgp_peer_index_seek(union sockunion* su)
* NB: it is a FATAL error to register a peer for an address which is already
* registered.
*/
-extern void
+void
bgp_peer_index_register(bgp_peer peer, union sockunion* su)
{
BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -184,8 +184,39 @@ bgp_peer_index_register(bgp_peer peer, union sockunion* su)
BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
- passert(peer != NULL) ;
-} ;
+ passert(peer == NULL) ;
+}
+
+/*------------------------------------------------------------------------------
+ * Unregister a peer in the peer index.
+ *
+ * returns 1 if successfully unregistered
+ * returns 0 if wasn't registered
+ * FATAL error if a different peer is registered.
+ */
+int
+bgp_peer_index_unregister(bgp_peer peer, union sockunion* su)
+{
+ int found = 0;
+ int right_peer = 1;
+ symbol s = NULL;
+
+ BGP_PEER_INDEX_LOCK() ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ s = symbol_seek(&bgp_peer_index, su);
+ found = (s != NULL);
+ if (found)
+ {
+ right_peer = (peer == symbol_get_value(s));
+ if (right_peer)
+ symbol_delete(s);
+ }
+
+ BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ passert(right_peer) ;
+ return found;
+}
/*------------------------------------------------------------------------------
* Lookup a session -- do nothing if does not exist
@@ -222,7 +253,7 @@ bgp_session_index_seek(union sockunion* su, int* p_found)
BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
return session ;
-} ;
+}
/*------------------------------------------------------------------------------
* Set peer's session pointer.
@@ -237,8 +268,8 @@ bgp_session_index_seek(union sockunion* su, int* p_found)
*
*/
-extern bgp_session
-bgp_session_index_seek(bgp_peer peer, bgp_session new_session)
+bgp_session
+bgp_peer_new_session(bgp_peer peer, bgp_session new_session)
{
bgp_session old_session ;
@@ -252,7 +283,7 @@ bgp_session_index_seek(bgp_peer peer, bgp_session new_session)
BGP_PEER_INDEX_UNLOCK() ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
return old_session ;
-} ;
+}
@@ -281,33 +312,34 @@ bgp_peer_new_session_state(mqueue_block mqb, mqb_flag_t flag)
{
bgp_session_lock(session) ;
-
-
switch(new_state)
{
/* If now Enabled, then the BGP Engine is attempting to connect */
/* (may be waiting for the Idle Hold Time to expire. */
case bgp_session_Enabled:
+ bgp_session_enable(session, peer);
break ;
/* If now Established, then the BGP Engine has exchanged BGP Open */
/* messages, and received the KeepAlive that acknowledges our Open. */
case bgp_session_Established:
+ bgp_session_has_established(peer);
break ;
/* If now Stopped, then for some reason the BGP Engine has either */
/* stopped trying to connect, or the session has been stopped. */
case bgp_session_Stopped:
+ bgp_session_has_stopped(peer);
break ;
default:
- } ;
+ }
bgp_session_unlock(session) ;
- } ;
+ }
mqb_free(mqb) ;
-} ;
+}
/* BGP Session has been Established.
*
@@ -323,6 +355,9 @@ bgp_session_has_established(bgp_peer peer)
safi_t safi;
int nsf_af_count = 0;
+ /* update peer state from received open */
+ bgp_peer_open_state_receive(peer);
+
/* Reset capability open status flag. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
@@ -428,7 +463,7 @@ bgp_session_has_established(bgp_peer peer)
/* Administrative BGP peer stop event. */
/* May be called multiple times for the same peer */
static int
-bgp_session_has_stopped(bgp_peer *peer)
+bgp_session_has_stopped(bgp_peer peer)
{
afi_t afi;
safi_t safi;
@@ -555,8 +590,6 @@ bgp_session_has_stopped(bgp_peer *peer)
return 0;
}
-
-
/* Stop all timers for the given peer
*/
static void
@@ -570,11 +603,6 @@ bgp_peer_timers_stop(bgp_peer peer)
BGP_TIMER_OFF (peer->t_pmax_restart);
} ;
-
-
-
-
-
void
bgp_timer_set (struct peer *peer)
{
@@ -632,7 +660,6 @@ bgp_timer_set (struct peer *peer)
}
}
-
static int
bgp_routeadv_timer (struct thread *thread)
{
@@ -744,7 +771,7 @@ bgp_graceful_stale_timer_expire (struct thread *thread)
}
-/* BGP peer is stoped by the error. */
+/* BGP peer is stopped by the error. */
static int
bgp_stop_with_error (struct peer *peer)
{
@@ -760,3 +787,304 @@ bgp_stop_with_error (struct peer *peer)
return 0;
}
+/* Allocate new peer object, implicitly locked. */
+struct peer *
+peer_new (struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ struct servent *sp;
+
+ /* bgp argument is absolutely required */
+ assert (bgp);
+ if (!bgp)
+ return NULL;
+
+ /* Allocate new peer. */
+ peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
+
+ /* Set default value. */
+ peer->fd = -1;
+ peer->v_start = BGP_INIT_START_TIMER;
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
+ peer->status = Idle;
+ peer->ostatus = Idle;
+ peer->weight = 0;
+ peer->password = NULL;
+ peer->bgp = bgp;
+ peer = peer_lock (peer); /* initial reference */
+ bgp_lock (bgp);
+
+ /* Set default flags. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (! bgp_option_check (BGP_OPT_CONFIG_CISCO))
+ {
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+ }
+ peer->orf_plist[afi][safi] = NULL;
+ }
+ SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+
+ /* Create buffers. */
+ peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE);
+ peer->obuf = stream_fifo_new ();
+ peer->work = stream_new (BGP_MAX_PACKET_SIZE);
+
+ bgp_sync_init (peer);
+
+ /* Get service port number. */
+ sp = getservbyname ("bgp", "tcp");
+ peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port);
+
+ return peer;
+}
+
+/* Create new BGP peer. */
+struct peer *
+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;
+ char buf[SU_ADDRSTRLEN];
+
+ 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->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 */
+ listnode_add_sort (bgp->peer, peer);
+
+ active = peer_active (peer);
+
+ if (afi && safi)
+ peer->afc[afi][safi] = 1;
+
+ /* Last read time set */
+ peer->readtime = time (NULL);
+
+ /* Last reset time set */
+ peer->resettime = time (NULL);
+
+ /* Default TTL set. */
+ peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1);
+
+ /* Make peer's address string. */
+ sockunion2str (su, buf, SU_ADDRSTRLEN);
+ peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
+
+ /* Set up peer's events and timers. */
+ if (! active && peer_active (peer))
+ bgp_timer_set (peer);
+
+ /* session */
+ peer->session = bgp_session_init_new(NULL);
+
+ /* register */
+ bgp_peer_index_register(peer, &peer->su);
+
+ return peer;
+}
+
+/* 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)
+{
+ int i;
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+ struct bgp_filter *filter;
+ struct listnode *pn;
+
+ assert (peer->status != Deleted);
+
+ bgp = peer->bgp;
+
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop (peer);
+
+ /* 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;
+ }
+
+ /* 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.
+ */
+ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
+ bgp_stop (peer);
+ bgp_fsm_change_status (peer, Deleted);
+
+ /* Password configuration */
+ if (peer->password)
+ {
+ XFREE (MTYPE_PEER_PASSWORD, peer->password);
+ peer->password = NULL;
+
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ bgp_md5_set (peer);
+ }
+
+ 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)))
+ {
+ 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);
+
+ /* 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 (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT);
+ }
+
+ /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not
+ member of a peer_group. */
+ 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]);
+
+ /* Buffers. */
+ if (peer->ibuf)
+ stream_free (peer->ibuf);
+ if (peer->obuf)
+ stream_fifo_free (peer->obuf);
+ if (peer->work)
+ stream_free (peer->work);
+ peer->obuf = NULL;
+ peer->work = peer->ibuf = NULL;
+
+ /* Local and remote addresses. */
+ if (peer->su_local)
+ sockunion_free (peer->su_local);
+ if (peer->su_remote)
+ sockunion_free (peer->su_remote);
+ peer->su_local = peer->su_remote = NULL;
+
+ /* Free filter related memory. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ filter = &peer->filter[afi][safi];
+
+ for (i = FILTER_IN; i < FILTER_MAX; i++)
+ {
+ if (filter->dlist[i].name)
+ free (filter->dlist[i].name);
+ if (filter->aslist[i].name)
+ free (filter->aslist[i].name);
+ filter->dlist[i].name = NULL;
+ prefix_list_unset_ref(&filter->plist[i].ref) ;
+ filter->aslist[i].name = NULL;
+ }
+ for (i = RMAP_IN; i < RMAP_MAX; i++)
+ {
+ if (filter->map[i].name)
+ free (filter->map[i].name);
+ filter->map[i].name = NULL;
+ }
+
+ if (filter->usmap.name)
+ free (filter->usmap.name);
+
+ if (peer->default_rmap[afi][safi].name)
+ free (peer->default_rmap[afi][safi].name);
+
+ filter->usmap.name = NULL;
+ peer->default_rmap[afi][safi].name = NULL;
+ }
+
+ /* unregister */
+ if (peer->su)
+ bgp_peer_index_unregister(peer, &peer->su);
+
+ peer_unlock (peer); /* initial reference */
+
+ return 0;
+}
+
+void
+peer_free (struct peer *peer)
+{
+ assert (peer->status == Deleted);
+
+ bgp_unlock(peer->bgp);
+
+ /* this /ought/ to have been done already through bgp_stop earlier,
+ * but just to be sure..
+ */
+ bgp_timer_set (peer);
+ BGP_READ_OFF (peer->t_read);
+ BGP_WRITE_OFF (peer->t_write);
+ BGP_EVENT_FLUSH (peer);
+
+ if (peer->desc)
+ XFREE (MTYPE_PEER_DESC, peer->desc);
+
+ /* Free allocated host character. */
+ if (peer->host)
+ XFREE (MTYPE_BGP_PEER_HOST, peer->host);
+
+ /* Update source configuration. */
+ if (peer->update_source)
+ sockunion_free (peer->update_source);
+
+ 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));
+
+ XFREE (MTYPE_BGP_PEER, peer);
+}
diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h
index e0de8930..049a3805 100644
--- a/bgpd/bgp_peer.h
+++ b/bgpd/bgp_peer.h
@@ -467,5 +467,18 @@ bgp_peer_index_register(bgp_peer peer, union sockunion* su) ;
extern bgp_session
bgp_session_index_seek(union sockunion* su, int* p_found) ;
+extern struct peer *
+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);
+
+extern int
+peer_delete (struct peer *peer);
+
+extern void
+peer_free (struct peer *peer);
+
#endif /* _QUAGGA_BGP_PEER_H */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index adb8264e..61e960f1 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -683,43 +683,6 @@ peer_sort (struct peer *peer)
}
}
-static inline void
-peer_free (struct peer *peer)
-{
- assert (peer->status == Deleted);
-
- bgp_unlock(peer->bgp);
-
- /* this /ought/ to have been done already through bgp_stop earlier,
- * but just to be sure..
- */
- bgp_timer_set (peer);
- BGP_READ_OFF (peer->t_read);
- BGP_WRITE_OFF (peer->t_write);
- BGP_EVENT_FLUSH (peer);
-
- if (peer->desc)
- XFREE (MTYPE_PEER_DESC, peer->desc);
-
- /* Free allocated host character. */
- if (peer->host)
- XFREE (MTYPE_BGP_PEER_HOST, peer->host);
-
- /* Update source configuration. */
- if (peer->update_source)
- sockunion_free (peer->update_source);
-
- if (peer->update_if)
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-
- if (peer->clear_node_queue)
- work_queue_free (peer->clear_node_queue);
-
- bgp_sync_delete (peer);
- memset (peer, 0, sizeof (struct peer));
-
- XFREE (MTYPE_BGP_PEER, peer);
-}
/* increase reference count on a struct peer */
struct peer *
@@ -763,111 +726,6 @@ peer_unlock (struct peer *peer)
return peer;
}
-/* Allocate new peer object, implicitely locked. */
-static struct peer *
-peer_new (struct bgp *bgp)
-{
- afi_t afi;
- safi_t safi;
- struct peer *peer;
- struct servent *sp;
-
- /* bgp argument is absolutely required */
- assert (bgp);
- if (!bgp)
- return NULL;
-
- /* Allocate new peer. */
- peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
-
- /* Set default value. */
- peer->fd = -1;
- peer->v_start = BGP_INIT_START_TIMER;
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- peer->v_asorig = BGP_DEFAULT_ASORIGINATE;
- peer->status = Idle;
- peer->ostatus = Idle;
- peer->weight = 0;
- peer->password = NULL;
- peer->bgp = bgp;
- peer = peer_lock (peer); /* initial reference */
- bgp_lock (bgp);
-
- /* Set default flags. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (! bgp_option_check (BGP_OPT_CONFIG_CISCO))
- {
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
- }
- peer->orf_plist[afi][safi] = NULL;
- }
- SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
-
- /* Create buffers. */
- peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE);
- peer->obuf = stream_fifo_new ();
- peer->work = stream_new (BGP_MAX_PACKET_SIZE);
-
- bgp_sync_init (peer);
-
- /* Get service port number. */
- sp = getservbyname ("bgp", "tcp");
- peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port);
-
- return peer;
-}
-
-/* Create new BGP peer. */
-static struct peer *
-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;
- char buf[SU_ADDRSTRLEN];
-
- 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->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 */
- listnode_add_sort (bgp->peer, peer);
-
- active = peer_active (peer);
-
- if (afi && safi)
- peer->afc[afi][safi] = 1;
-
- /* Last read time set */
- peer->readtime = time (NULL);
-
- /* Last reset time set */
- peer->resettime = time (NULL);
-
- /* Default TTL set. */
- peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1);
-
- /* Make peer's address string. */
- sockunion2str (su, buf, SU_ADDRSTRLEN);
- peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
-
- /* Set up peer's events and timers. */
- if (! active && peer_active (peer))
- bgp_timer_set (peer);
-
- return peer;
-}
/* Make accept BGP peer. Called from bgp_accept (). */
struct peer *
@@ -1156,149 +1014,7 @@ peer_nsf_stop (struct peer *peer)
bgp_clear_route_all (peer);
}
-/* Delete peer from confguration.
- *
- * 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)
-{
- int i;
- afi_t afi;
- safi_t safi;
- struct bgp *bgp;
- struct bgp_filter *filter;
- struct listnode *pn;
-
- assert (peer->status != Deleted);
- bgp = peer->bgp;
-
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
-
- /* 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;
- }
-
- /* 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.
- */
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_stop (peer);
- bgp_fsm_change_status (peer, Deleted);
-
- /* Password configuration */
- if (peer->password)
- {
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- bgp_md5_set (peer);
- }
-
- 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)))
- {
- 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);
-
- /* 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 (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT);
- }
-
- /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not
- member of a peer_group. */
- 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]);
-
- /* Buffers. */
- if (peer->ibuf)
- stream_free (peer->ibuf);
- if (peer->obuf)
- stream_fifo_free (peer->obuf);
- if (peer->work)
- stream_free (peer->work);
- peer->obuf = NULL;
- peer->work = peer->ibuf = NULL;
-
- /* Local and remote addresses. */
- if (peer->su_local)
- sockunion_free (peer->su_local);
- if (peer->su_remote)
- sockunion_free (peer->su_remote);
- peer->su_local = peer->su_remote = NULL;
-
- /* Free filter related memory. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
-
- for (i = FILTER_IN; i < FILTER_MAX; i++)
- {
- if (filter->dlist[i].name)
- free (filter->dlist[i].name);
- if (filter->aslist[i].name)
- free (filter->aslist[i].name);
- filter->dlist[i].name = NULL;
- prefix_list_unset_ref(&filter->plist[i].ref) ;
- filter->aslist[i].name = NULL;
- }
- for (i = RMAP_IN; i < RMAP_MAX; i++)
- {
- if (filter->map[i].name)
- free (filter->map[i].name);
- filter->map[i].name = NULL;
- }
-
- if (filter->usmap.name)
- free (filter->usmap.name);
-
- if (peer->default_rmap[afi][safi].name)
- free (peer->default_rmap[afi][safi].name);
-
- filter->usmap.name = NULL;
- peer->default_rmap[afi][safi].name = NULL;
- }
-
- peer_unlock (peer); /* initial reference */
-
- return 0;
-}
static int
peer_group_cmp (struct peer_group *g1, struct peer_group *g2)
@@ -2641,6 +2357,8 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
peer->ttl = ttl;
+ /* TODO: peer-fd doesn't exist */
+#if 0
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
@@ -2660,6 +2378,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
}
}
+#endif
return 0;
}
@@ -2677,6 +2396,8 @@ peer_ebgp_multihop_unset (struct peer *peer)
else
peer->ttl = 1;
+ /* TODO: peer-fd doesn't exist */
+#if 0
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
@@ -2696,6 +2417,7 @@ peer_ebgp_multihop_unset (struct peer *peer)
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
}
}
+#endif
return 0;
}
@@ -5080,6 +4802,9 @@ bgp_master_init (void)
void
bgp_init (void)
{
+ /* peer index */
+ bgp_peer_index_init(NULL);
+
/* BGP VTY commands installation. */
bgp_vty_init ();
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 92fd3883..acf99074 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_common.h"
#include "bgpd/bgp_notification.h"
+#include "bgpd/bgp_peer.h"
#include "plist.h"
diff --git a/lib/command_queue.c b/lib/command_queue.c
index 69c8eca6..3bb3473f 100644
--- a/lib/command_queue.c
+++ b/lib/command_queue.c
@@ -29,34 +29,18 @@
/* Prototypes */
static void cq_action(mqueue_block mqb, mqb_flag_t flag);
-/* We have too many parameters for a message queue block so have to marshal */
-struct marshal
-{
- struct cmd_element *matched_element;
- struct vty *vty;
- int argc;
- char **argv;
-};
-
void
cq_enqueue(struct cmd_element *matched_element, struct vty *vty,
int argc, const char *argv[], qpn_nexus bgp_nexus)
{
- struct marshal *wyatt = XCALLOC(MTYPE_MARSHAL, sizeof(struct marshal)) ;
int i;
- mqueue_block mqb = NULL;
+ mqueue_block mqb = mqb_init_new(NULL, cq_action, matched_element) ;
- wyatt->matched_element = matched_element;
- wyatt->vty = vty;
- wyatt->argc = argc;
- wyatt->argv = argc ? XCALLOC(MTYPE_MARSHAL, sizeof (char*) * argc) : NULL;
+ /* all parameters are pointers so use the queue's argv */
+ mqb_push_argv_p(mqb, vty);
for (i = 0; i < argc; ++i)
- {
- wyatt->argv[i] = XSTRDUP(MTYPE_MARSHAL, argv[i]);
- }
+ mqb_push_argv_p(mqb, XSTRDUP(MTYPE_MARSHAL, argv[i]));
- mqb = mqb_init_new(mqb, cq_action, 0) ;
- mqb->arg0 = wyatt;
mqueue_enqueue(bgp_nexus->queue, mqb, 0) ;
}
@@ -66,25 +50,32 @@ cq_action(mqueue_block mqb, mqb_flag_t flag)
{
int result;
int i;
- struct marshal *wyatt = mqb->arg0;
+ struct cmd_element *matched_element;
+ struct vty *vty;
+ void **argv;
+ int argc;
+
+ matched_element = mqb_get_arg0(mqb);
+ argc = mqb_get_argv_count(mqb);
+ argv = mqb_get_argv(mqb) ;
+
+ vty = argv[0];
+ argv++;
+ argc--;
if (flag == mqb_action)
{
/* Execute matched command. */
- result = (*wyatt->matched_element->func)
- (wyatt->matched_element, wyatt->vty, wyatt->argc, (const char **)wyatt->argv);
+ result = (matched_element->func)
+ (matched_element, vty, argc, (const char **)argv);
/* report */
- vty_queued_result(wyatt->vty, result);
+ vty_queued_result(vty, result);
}
/* clean up */
- for (i = 0; i< wyatt->argc; ++i)
- {
- XFREE(MTYPE_MARSHAL, wyatt->argv[i]);
- }
- if (wyatt->argv)
- XFREE(MTYPE_MARSHAL, wyatt->argv);
- XFREE(MTYPE_MARSHAL, wyatt);
+ for (i = 0; i < argc; ++i)
+ XFREE(MTYPE_MARSHAL, argv[i]);
+
mqb_free(mqb);
}
diff --git a/lib/qpnexus.c b/lib/qpnexus.c
index d8a8bbc6..5ecb97cf 100644
--- a/lib/qpnexus.c
+++ b/lib/qpnexus.c
@@ -27,14 +27,15 @@
#include "sigevent.h"
/* prototypes */
-static void* qpn_start_main(void* arg);
+static void* qpn_start(void* arg);
static void* qpn_start_bgp(void* arg);
+static void qpn_in_thread_init(qpn_nexus qpn);
/* Master of the threads. */
extern struct thread_master *master;
/*==============================================================================
- * Quagga Nexus Interface -- qpt_xxxx
+ * Quagga Nexus Interface -- qpn_xxxx
*
*/
@@ -44,9 +45,9 @@ extern struct thread_master *master;
* If main_thread is set then no new thread will be created
* when qpn_exec() is called, instead the finite state machine will be
* run in the calling thread. The main thread will only block the
- * message queue's signal. Non main threads will block all signals.
+ * message queue's signal. Non-main threads will block most signals.
*
- * Returns the qtn_nexus.
+ * Returns the qpn_nexus.
*/
qpn_nexus
qpn_init_new(qpn_nexus qpn)
@@ -59,21 +60,21 @@ qpn_init_new(qpn_nexus qpn)
return qpn;
}
-/* Initialize main qpthread, no queue */
+/* Initialize main qpthread */
qpn_nexus
qpn_init_main(qpn_nexus qpn)
{
qpn = qpn_init_new(qpn);
-
qpn->selection = qps_selection_init_new(qpn->selection);
qpn->pile = qtimer_pile_init_new(qpn->pile);
+ qpn->queue = mqueue_init_new(qpn->queue, mqt_signal_unicast);
qpn->main_thread = 1;
- qpn->start = qpn_start_main;
+ qpn->start = qpn_start;
return qpn;
}
-/* Initialize bgp qpthread */
+/* Initialize bgp engine's qpthread */
qpn_nexus
qpn_init_bgp(qpn_nexus qpn)
{
@@ -84,6 +85,24 @@ qpn_init_bgp(qpn_nexus qpn)
return qpn;
}
+/* Initialize Routing engine's qpthread
+ *
+ * Although not expected to do I/O we still use qps_selection (pselect) as
+ * the mechanism to wait for either a timeout or a signal from the message
+ * queue.
+*/
+qpn_nexus
+qpn_init_routing(qpn_nexus qpn)
+{
+ qpn = qpn_init_new(qpn);
+ qpn->selection = qps_selection_init_new(qpn->selection);
+ qpn->pile = qtimer_pile_init_new(qpn->pile);
+ qpn->queue = mqueue_init_new(qpn->queue, mqt_signal_unicast);
+ qpn->start = qpn_start;
+
+ return qpn;
+}
+
/* free timers, selection, message queue and nexus
* return NULL
*/
@@ -100,21 +119,19 @@ qpn_free(qpn_nexus qpn)
if (qpn->pile != NULL)
{
while ((qtr = qtimer_pile_ream(qpn->pile, 1)))
- {
qtimer_free(qtr);
- }
}
/* files and selection */
if (qpn->selection != NULL)
{
while ((qf = qps_selection_ream(qpn->selection, 1)))
- {
qps_file_free(qf);
- }
}
- /* TODO: free qtn->queue */
+ /* TODO: free qpn->queue */
+ /* TODO: free qpn->mts */
+
XFREE(MTYPE_QPN_NEXUS, qpn) ;
@@ -138,30 +155,26 @@ qpn_exec(qpn_nexus qpn)
}
}
-/* Main qpthread, prep signals, then run finite state machine
- * using qps_selection and qtimer
+/* Thread routine, complete init, then run finite state machine
+ * using mqueue, qps_selection and qtimer
*/
static void*
-qpn_start_main(void* arg)
+qpn_start(void* arg)
{
qpn_nexus qpn = arg;
+ mqueue_block mqb;
int actions;
qtime_mono_t now;
- sigset_t newmask;
- qpn->thread_id = qpt_thread_self();
-
- /* Main thread, block the message queue's signal */
- sigemptyset (&newmask);
- sigaddset (&newmask, SIGMQUEUE);
- qpt_thread_sigmask(SIG_BLOCK, &newmask, NULL);
- qps_set_signal(qpn->selection, SIGMQUEUE, newmask);
+ /* now in our thread, complete initialisation */
+ qpn_in_thread_init(qpn);
while (!qpn->terminate)
{
/* Signals are highest priority.
* only execute on the main thread */
- quagga_sigevent_process ();
+ if (qpn->main_thread)
+ quagga_sigevent_process ();
/* process timers */
now = qt_get_monotonic();
@@ -169,21 +182,31 @@ qpn_start_main(void* arg)
{
}
- /* block for some input, output or timeout */
- actions = qps_pselect( qpn->selection,
+ /* drain the message queue, will be waiting when it's empty */
+ for (;;)
+ {
+ mqb = mqueue_dequeue(qpn->queue, 1, qpn->mts) ;
+ if (mqb == NULL)
+ break;
+
+ mqb_dispatch(mqb, mqb_action);
+ }
+
+ /* block for some input, output, signal or timeout */
+ actions = qps_pselect(qpn->selection,
qtimer_pile_top_time(qpn->pile, now + QTIME(MAX_PSELECT_TIMOUT)) );
/* process I/O actions */
while (actions)
- {
actions = qps_dispatch_next(qpn->selection) ;
- }
+
+ mqueue_done_waiting(qpn->queue, qpn->mts);
}
return NULL;
}
-/* Bgp prep signals, then run finite state machine
+/* Bgp engine's qpthread, complete init, then run finite state machine
* using legacy threads
*/
static void*
@@ -192,33 +215,12 @@ qpn_start_bgp(void* arg)
qpn_nexus qpn = arg;
struct thread thread;
mqueue_block mqb;
- sigset_t newmask;
-
- qpn->thread_id = qpt_thread_self();
- /*
- * Not main thread. Block most signals, but be careful not to
- * defer SIGTRAP because doing so breaks gdb, at least on
- * NetBSD 2.0. Avoid asking to block SIGKILL, just because
- * we shouldn't be able to do so. Avoid blocking SIGFPE,
- * SIGILL, SIGSEGV, SIGBUS as this is undefined by POSIX.
- * Don't block SIGPIPE so that is gets ignored on this thread.
- */
- sigfillset (&newmask);
- sigdelset (&newmask, SIGTRAP);
- sigdelset (&newmask, SIGKILL);
- sigdelset (&newmask, SIGPIPE);
- sigdelset (&newmask, SIGFPE);
- sigdelset (&newmask, SIGILL);
- sigdelset (&newmask, SIGSEGV);
- sigdelset (&newmask, SIGBUS);
-
- qpt_thread_sigmask(SIG_BLOCK, &newmask, NULL);
- qpn->mts = mqueue_thread_signal_init(qpn->mts, qpn->thread_id, SIGMQUEUE);
+ /* now in our thread, complete initialisation */
+ qpn_in_thread_init(qpn);
while (!qpn->terminate)
{
-
/* drain the message queue, will be waiting when it's empty */
for (;;)
{
@@ -239,6 +241,48 @@ qpn_start_bgp(void* arg)
return NULL;
}
+/* Now running in our thread, complete initialisation */
+static void
+qpn_in_thread_init(qpn_nexus qpn)
+{
+ sigset_t newmask;
+
+ qpn->thread_id = qpt_thread_self();
+
+ if (qpn->main_thread)
+ {
+ /* Main thread, block the message queue's signal */
+ sigemptyset (&newmask);
+ sigaddset (&newmask, SIGMQUEUE);
+ }
+ else
+ {
+ /*
+ * Not main thread. Block most signals, but be careful not to
+ * defer SIGTRAP because doing so breaks gdb, at least on
+ * NetBSD 2.0. Avoid asking to block SIGKILL, just because
+ * we shouldn't be able to do so. Avoid blocking SIGFPE,
+ * SIGILL, SIGSEGV, SIGBUS as this is undefined by POSIX.
+ * Don't block SIGPIPE so that is gets ignored on this thread.
+ */
+ sigfillset (&newmask);
+ sigdelset (&newmask, SIGTRAP);
+ sigdelset (&newmask, SIGKILL);
+ sigdelset (&newmask, SIGPIPE);
+ sigdelset (&newmask, SIGFPE);
+ sigdelset (&newmask, SIGILL);
+ sigdelset (&newmask, SIGSEGV);
+ sigdelset (&newmask, SIGBUS);
+ }
+ qpt_thread_sigmask(SIG_BLOCK, &newmask, NULL);
+
+ /* Now we have thread_id and mask, prep for using message queue. */
+ if (qpn->queue != NULL)
+ qpn->mts = mqueue_thread_signal_init(qpn->mts, qpn->thread_id, SIGMQUEUE);
+ if (qpn->selection != NULL)
+ qps_set_signal(qpn->selection, SIGMQUEUE, newmask);
+}
+
/* Ask the thread to terminate itself quickly and cleanly */
void
qpn_terminate(qpn_nexus qpn)
diff --git a/lib/qpnexus.h b/lib/qpnexus.h
index 7436c55d..69fe8044 100644
--- a/lib/qpnexus.h
+++ b/lib/qpnexus.h
@@ -92,6 +92,7 @@ struct qpn_nexus
extern qpn_nexus qpn_init_new(qpn_nexus qtn);
extern qpn_nexus qpn_init_main(qpn_nexus qtn);
extern qpn_nexus qpn_init_bgp(qpn_nexus qtn);
+extern qpn_nexus qpn_init_routing(qpn_nexus qtn);
extern void qpn_exec(qpn_nexus qtn);
extern void qpn_terminate(qpn_nexus qpn);
extern qpn_nexus qpn_free(qpn_nexus qpn);