diff options
Diffstat (limited to 'bgpd/bgp_open_state.c')
-rw-r--r-- | bgpd/bgp_open_state.c | 141 |
1 files changed, 132 insertions, 9 deletions
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]; + } + +} |