diff options
-rw-r--r-- | bgpd/bgp_main.c | 25 | ||||
-rw-r--r-- | bgpd/bgp_open_state.c | 141 | ||||
-rw-r--r-- | bgpd/bgp_open_state.h | 5 | ||||
-rw-r--r-- | bgpd/bgp_peer.c | 384 | ||||
-rw-r--r-- | bgpd/bgp_peer.h | 13 | ||||
-rw-r--r-- | bgpd/bgpd.c | 293 | ||||
-rw-r--r-- | bgpd/bgpd.h | 1 | ||||
-rw-r--r-- | lib/command_queue.c | 53 | ||||
-rw-r--r-- | lib/qpnexus.c | 150 | ||||
-rw-r--r-- | lib/qpnexus.h | 1 |
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); |