In the case of a route being and there is not an alternate
[mpls-ldp-portable.git] / ldp / ldp_hello.c
blobf031d398336f9e205ad145654bb591399d6efbb2
2 /*
3 * Copyright (C) James R. Leu 2000
4 * jleu@mindspring.com
6 * This software is covered under the LGPL, for more
7 * info check out http://www.gnu.org/copyleft/lgpl.html
8 */
10 #include <stdio.h>
11 #include <sys/socket.h>
13 #include "ldp_struct.h"
14 #include "ldp_hello.h"
15 #include "ldp_mesg.h"
16 #include "ldp_buf.h"
17 #include "ldp_adj.h"
18 #include "ldp_hello.h"
19 #include "ldp_entity.h"
20 #include "ldp_session.h"
21 #include "ldp_inet_addr.h"
22 #include "ldp_pdu_setup.h"
24 #include "mpls_assert.h"
25 #include "mpls_socket_impl.h"
26 #include "mpls_timer_impl.h"
27 #include "mpls_lock_impl.h"
28 #include "mpls_trace_impl.h"
30 void ldp_hello_timeout_callback(mpls_timer_handle timer, void *extra,
31 mpls_cfg_handle handle)
33 ldp_adj *a = (ldp_adj *) extra;
34 ldp_global *g = (ldp_global*)handle;
36 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
37 "Hello Timout fired: adj(%d)\n", a->index);
39 mpls_lock_get(g->global_lock);
41 if (a->session) {
42 a->session->shutdown_notif = LDP_NOTIF_HOLD_TIMER_EXPIRED;
43 a->session->shutdown_fatal = MPLS_BOOL_FALSE;
45 ldp_adj_shutdown(g, a);
46 /* timer is deleted inside of ldp_adj_shutdown */
47 /* the refcount release for the time is done in ldp_adj_shutdown as well */
49 mpls_lock_release(g->global_lock);
52 void ldp_hello_send_callback(mpls_timer_handle timer, void *extra,
53 mpls_cfg_handle handle)
55 ldp_entity *e = (ldp_entity*)extra;
56 ldp_global *g = (ldp_global*)handle;
58 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
59 "Hello Send fired: entity(%d)\n", e->index);
61 mpls_lock_get(g->global_lock);
63 ldp_hello_send(g, e);
65 mpls_lock_release(g->global_lock);
68 mpls_return_enum ldp_hello_send(ldp_global * g, ldp_entity * e)
70 ldp_mesg **hello = NULL;
71 mpls_timer_handle *timer;
72 int *oper_duration = 0;
73 int targeted = 0;
74 int duration = 0;
75 int request = 0;
77 MPLS_ASSERT(g != NULL && e != NULL);
79 switch (e->entity_type) {
80 case LDP_DIRECT:
81 MPLS_ASSERT(e->p.iff != NULL);
82 hello = &e->p.iff->hello;
83 oper_duration = &e->p.iff->hellotime_send_timer_duration;
84 timer = &e->p.iff->hellotime_send_timer;
85 targeted = 0;
86 request = 0;
87 break;
88 case LDP_INDIRECT:
89 MPLS_ASSERT(e->p.peer != NULL);
90 hello = &e->p.peer->hello;
91 oper_duration = &e->p.peer->hellotime_send_timer_duration;
92 timer = &e->p.peer->hellotime_send_timer;
93 targeted = 1;
94 if (e->p.peer->target_role == LDP_ACTIVE) {
95 request = 1;
96 } else {
97 request = 0;
99 break;
100 default:
101 MPLS_ASSERT(0);
103 if (!*hello) {
104 *hello = ldp_hello_create(g->message_identifier++,
105 e->hellotime_timer, &e->transport_address,
106 g->configuration_sequence_number, targeted, request);
109 duration = e->hellotime_interval;
111 if (mpls_timer_handle_verify(g->timer_handle, *timer) == MPLS_BOOL_FALSE) {
112 MPLS_REFCNT_HOLD(e);
113 *timer = mpls_timer_create(g->timer_handle, MPLS_UNIT_SEC,
114 duration, (void *)e, g, ldp_hello_send_callback);
115 if (mpls_timer_handle_verify(g->timer_handle, *timer) == MPLS_BOOL_FALSE) {
116 *oper_duration = 0;
117 MPLS_REFCNT_RELEASE(e, ldp_entity_delete);
118 return MPLS_FAILURE;
120 *oper_duration = duration;
121 mpls_timer_start(g->timer_handle, *timer, MPLS_TIMER_REOCCURRING);
122 } else {
123 if ((*oper_duration) != duration) {
124 mpls_timer_stop(g->timer_handle, *timer);
125 *oper_duration = duration;
126 mpls_timer_modify(g->timer_handle, *timer, duration);
127 mpls_timer_start(g->timer_handle, *timer, MPLS_TIMER_REOCCURRING);
131 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_PERIODIC,
132 "Hello Send: entity(%d)\n", e->index);
134 return ldp_mesg_send_udp(g, e, *hello);
137 ldp_mesg *ldp_hello_create(uint32_t msgid, int holdtime, mpls_inet_addr * traddr,
138 uint32_t confnum, int targeted, int request)
140 mplsLdpHelloMsg_t *hello = NULL;
141 ldp_mesg *msg = NULL;
143 msg = ldp_mesg_create();
144 ldp_mesg_prepare(msg, MPLS_HELLO_MSGTYPE, msgid);
145 if (msg != NULL) {
146 hello = &msg->u.hello;
148 hello->trAdrTlvExists = 0;
149 hello->csnTlvExists = 0;
151 hello->chpTlvExists = 1;
153 /* this assumes we always want to receive updates for targeted hellos */
154 hello->baseMsg.msgLength += setupChpTlv(&(hello->chp), targeted,
155 request, 0, holdtime);
157 if (traddr && traddr->type == MPLS_FAMILY_IPV4 && traddr->u.ipv4 > 0) {
158 hello->trAdrTlvExists = 1;
159 hello->baseMsg.msgLength +=
160 setupTrAddrTlv(&(hello->trAdr), traddr->u.ipv4);
163 if (confnum > 0) {
164 hello->csnTlvExists = 1;
165 hello->baseMsg.msgLength += setupCsnTlv(&(hello->csn), confnum);
168 return msg;
171 mpls_return_enum ldp_hello_process(ldp_global * g, ldp_adj * a, ldp_entity *e,
172 int hellotime, uint32_t csn, mpls_inet_addr * traddr, int targeted,
173 int request)
175 mpls_inet_addr *local = NULL, *remote = NULL;
177 MPLS_ASSERT(a && e);
179 LDP_ENTER(g->user_data, "ldp_hello_process: a = %p, e = %p", a, e);
181 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_PERIODIC,
182 "Hello Recv: entity(%d)\n", e->index);
184 switch (e->entity_type) {
185 case LDP_DIRECT:
186 /* ldp-11 3.5.2. Hello Message */
187 if (hellotime == 0) {
188 hellotime = 15;
191 if (MPLS_LIST_HEAD(&e->p.iff->addr_root)) {
192 local = &(MPLS_LIST_HEAD(&e->p.iff->addr_root)->address);
193 } else {
194 local = &g->lsr_identifier;
197 break;
198 case LDP_INDIRECT:
199 /* ldp-11 3.5.2. Hello Message */
200 if (hellotime == 0) {
201 hellotime = 45;
204 local = &g->lsr_identifier;
205 break;
206 default:
207 MPLS_ASSERT(0);
210 if (hellotime < e->hellotime_timer) {
211 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_NORMAL,
212 "ldp_hello_process: adjusting hellotime_timer to match adj\n");
213 e->hellotime_timer = hellotime;
216 if (traddr != NULL) {
217 memcpy(&a->remote_transport_address, traddr, sizeof(struct mpls_inet_addr));
220 if (csn != a->remote_csn) {
221 /* the remote csn changes all we can do is clear the backoff time */
222 /* this will only enable a lsr in the active role to try again */
223 a->remote_csn = csn;
224 if (a->session && mpls_timer_handle_verify(g->timer_handle,
225 a->session->backoff_timer) == MPLS_BOOL_TRUE) {
226 ldp_session_backoff_stop(g, a->session);
230 /* JLEU should verify that the hello hasn't changed */
232 if (a->session) {
233 /* && a->session->state == LDP_STATE_OPERATIONAL) */
234 /* all that matters is that we have a session in progress */
235 /* we already have an established session */
236 LDP_EXIT(g->user_data, "ldp_hello_process");
237 return MPLS_SUCCESS;
240 if (e->transport_address.type != MPLS_FAMILY_NONE) {
241 local = &e->transport_address;
244 if (a->remote_transport_address.type != MPLS_FAMILY_NONE) {
245 remote = &a->remote_transport_address;
246 } else {
247 remote = &a->remote_source_address;
250 switch (mpls_inet_addr_compare(local, remote)) {
251 case 1:
252 /* if at one point we through WE were passive */
253 if (a->role == LDP_PASSIVE && a->session) {
254 ldp_session_shutdown(g, a->session, MPLS_BOOL_TRUE);
256 a->role = LDP_ACTIVE;
258 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
259 "ldp_hello_process: ACTIVE(%d)\n", a->index);
261 if (ldp_session_create_active(g, a) != MPLS_SUCCESS) {
262 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_NORMAL,
263 "ldp_hello_process: creating an active session failed(%d)\n",
264 a->index);
265 /* return FAILURE so we don't try to continue with the new adj */
266 return MPLS_FAILURE;
268 break;
269 case -1:
270 /* if at one point we through WE were active */
271 if (a->role == LDP_ACTIVE && a->session) {
272 ldp_session_shutdown(g, a->session, MPLS_BOOL_TRUE);
274 a->role = LDP_PASSIVE;
276 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
277 "ldp_hello_process: PASSIVE(%d)\n", a->index);
279 break;
280 default:
281 LDP_PRINT(g->user_data,
282 "ldp_hello_process: exit(%d) configuration error\n", a->index);
284 if (a->session) {
285 ldp_session_shutdown(g, a->session, MPLS_BOOL_TRUE);
287 a->role = LDP_NONE;
288 MPLS_ASSERT(a->session == NULL);
290 /* return FAILURE so we don't try to continue with the new adj */
291 LDP_EXIT(g->user_data, "ldp_hello_process: FAILURE");
292 return MPLS_FAILURE;
294 LDP_EXIT(g->user_data, "ldp_hello_process");
296 return MPLS_SUCCESS;