/* * Copyright (C) James R. Leu 2000 * jleu@mindspring.com * * This software is covered under the LGPL, for more * info check out http://www.gnu.org/copyleft/lgpl.html */ #include #include #include "ldp_struct.h" #include "ldp_assert.h" #include "ldp_entity.h" #include "ldp_range.h" #include "ldp_peer.h" #include "ldp_hello.h" #include "ldp_msg.h" #include "ldp_fib_impl.h" #include "ldp_ifmgr_impl.h" #include "ldp_lock_impl.h" #include "ldp_timer_impl.h" #include "ldp_mm_impl.h" #include "ldp_trace_impl.h" uint32_t _ldp_sub_entity_next_index = 1; void ldp_peer_retry_callback(ldp_timer_handle timer,void* extra, ldp_cfg_handle g) { ldp_peer* p = (ldp_peer*)extra; LDP_ENTER(g->user_data,"ldp_peer_retry_callback"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_TIMER, "Peer Retry Timer fired: peer(%d)\n",p->index); ldp_lock_get(g->global_lock); /* JLEU: should I hold a copy to make sure this doens't fail? */ ldp_peer_retry_stop(g,p); if(ldp_peer_startup(g,p) == LDP_FAILURE) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_ERROR, "Peer startup retry failure: peer (%d)\n",p->index); } ldp_lock_release(g->global_lock); LDP_EXIT(g->user_data,"ldp_peer_retry_callback"); } ldp_peer* ldp_peer_create() { ldp_peer* p = (ldp_peer*)ldp_malloc(sizeof(ldp_peer)); if(p) { memset(p,0,sizeof(ldp_peer)); LDP_REFCNT_INIT(p,0); LDP_LIST_ELEM_INIT(p,_global); LDP_LIST_ELEM_INIT(p,_range); p->label_space = -1; p->buffer_size = MPLS_PDUMAXLEN; p->index = _ldp_peer_get_next_index(); p->oper_state = LDP_DOWN; p->target_role = LDP_ACTIVE; } return p; } void ldp_peer_delete(ldp_peer* p) { // LDP_PRINT(g->user_data,"peer delete\n"); LDP_REFCNT_ASSERT(p,0); ldp_free(p); } ldp_return_enum ldp_peer_startup(ldp_global *g,ldp_peer *p) { ldp_entity *e = NULL; ldp_prefix dest; ldp_prefix entry[4]; LDP_ASSERT(p != NULL && ((e = p->entity) != NULL)); LDP_ENTER(g->user_data,"ldp_peer_startup"); p->dest.port = e->remote_udp_port; memcpy(&dest.network,&p->dest.addr,sizeof(ldp_inet_addr)); dest.prefix_len = 32; if(ldp_fib_get_best_route(g->fib_handle,4,&dest,entry) == 0) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_DEBUG, "ldp_peer_startup: exit(%d) no route to host\n",p->index); goto ldp_peer_startup_retry; } if(ldp_if_handle_verify(g->ifmgr_handle,entry[0].out_if_handle) == LDP_FALSE) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_DEBUG, "ldp_peer_startup: exit(%d) no such if\n",p->index); goto ldp_peer_startup_retry; } if(ldp_ifmgr_get_address(g->ifmgr_handle,entry[0].out_if_handle, &p->local_source_address,NULL,NULL) == LDP_FAILURE) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_DEBUG, "ldp_peer_startup: exit(%d) ifmgr failure\n",p->index); goto ldp_peer_startup_retry; } if(p->target_role == LDP_ACTIVE) { if(ldp_hello_send(g,e) == LDP_FAILURE) { goto ldp_peer_startup_retry; } } p->oper_state = LDP_UP; LDP_EXIT(g->user_data,"ldp_peer_startup"); return LDP_SUCCESS; ldp_peer_startup_retry: /* start a timer which will retry peer startup */ LDP_REFCNT_HOLD(p); p->oper_state = LDP_DOWN; p->no_route_to_peer_timer = ldp_timer_create(g->timer_handle,LDP_SEC, g->no_route_to_peer_time,(void*)p,g,ldp_peer_retry_callback); if(ldp_timer_handle_verify(g->timer_handle,p->no_route_to_peer_timer) == LDP_FALSE) { LDP_REFCNT_RELEASE(p,ldp_peer_delete); LDP_EXIT(g->user_data,"ldp_peer_startup-error"); return LDP_FAILURE; } ldp_timer_start(g->timer_handle,p->no_route_to_peer_timer,LDP_ONESHOT); LDP_EXIT(g->user_data,"ldp_peer_startup"); return LDP_SUCCESS; } void ldp_peer_retry_stop(ldp_global *g,ldp_peer *p) { LDP_ASSERT(p != NULL); LDP_ENTER(g->user_data,"ldp_peer_retry_stop"); if(ldp_timer_handle_verify(g->timer_handle,p->no_route_to_peer_timer) == LDP_TRUE) { ldp_timer_stop(g->timer_handle,p->no_route_to_peer_timer); ldp_timer_delete(g->timer_handle,p->no_route_to_peer_timer); p->no_route_to_peer_timer = 0; LDP_REFCNT_RELEASE(p,ldp_peer_delete); LDP_ASSERT(p != NULL); } LDP_EXIT(g->user_data,"ldp_peer_retry_stop"); } void ldp_peer_send_stop(ldp_global *g,ldp_peer *p) { ldp_entity *e = NULL; LDP_ASSERT(p != NULL && (e = p->entity) != NULL); LDP_ENTER(g->user_data,"ldp_peer_send_stop"); if(ldp_timer_handle_verify(g->timer_handle,p->hellotime_send_timer) == LDP_TRUE) { ldp_timer_stop(g->timer_handle,p->hellotime_send_timer); ldp_timer_delete(g->timer_handle,p->hellotime_send_timer); p->hellotime_send_timer_duration = 0; p->hellotime_send_timer = 0; LDP_REFCNT_RELEASE(e,ldp_entity_delete); LDP_ASSERT(e != NULL); } if(p->hello != NULL) { ldp_msg_delete(p->hello); p->hello = NULL; } LDP_EXIT(g->user_data,"ldp_peer_send_stop"); } ldp_return_enum ldp_peer_shutdown(ldp_global *g,ldp_peer *p) { LDP_ENTER(g->user_data,"ldp_peer_shutdown"); p->oper_state = LDP_DOWN; ldp_peer_send_stop(g,p); ldp_peer_retry_stop(g,p); LDP_EXIT(g->user_data,"ldp_peer_shutdown"); return LDP_SUCCESS; } ldp_bool ldp_peer_is_active(ldp_peer* p) { if(p && p->entity && p->entity->admin_state == LDP_ENABLE) return LDP_TRUE; return LDP_FALSE; } ldp_return_enum ldp_peer_add_range(ldp_peer* p,ldp_range* r) { if(p && r) { LDP_REFCNT_HOLD(r); p->range = r; p->label_space = r->label_space; _ldp_range_add_peer(r,p); return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum ldp_peer_del_range(ldp_peer* p) { if(p && p->range) { _ldp_range_del_peer(p->range,p); LDP_REFCNT_RELEASE(p->range,ldp_range_delete); p->range = NULL; p->label_space = -1; return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum _ldp_peer_add_entity(ldp_peer* p,ldp_entity* e) { if(p && e) { LDP_REFCNT_HOLD(e); p->entity = e; return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum _ldp_peer_del_entity(ldp_peer* p) { if(p && p->entity) { LDP_REFCNT_RELEASE(p->entity,ldp_entity_delete); p->entity = NULL; return LDP_SUCCESS; } return LDP_FAILURE; } ldp_entity *ldp_peer_get_entity(ldp_peer* p) { return p->entity; } uint32_t _ldp_peer_get_next_index() { uint32_t retval = _ldp_sub_entity_next_index; _ldp_sub_entity_next_index++; if(retval > _ldp_sub_entity_next_index++) { _ldp_sub_entity_next_index = 1; } return retval; }