3 * Copyright (C) James R. Leu 2000
6 * This software is covered under the LGPL, for more
7 * info check out http://www.gnu.org/copyleft/lgpl.html
11 #include <sys/socket.h>
13 #include "ldp_struct.h"
14 #include "ldp_hello.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
);
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
);
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;
77 MPLS_ASSERT(g
!= NULL
&& e
!= NULL
);
79 switch (e
->entity_type
) {
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
;
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
;
94 if (e
->p
.peer
->target_role
== LDP_ACTIVE
) {
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
) {
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
) {
117 MPLS_REFCNT_RELEASE(e
, ldp_entity_delete
);
120 *oper_duration
= duration
;
121 mpls_timer_start(g
->timer_handle
, *timer
, MPLS_TIMER_REOCCURRING
);
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
);
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
);
164 hello
->csnTlvExists
= 1;
165 hello
->baseMsg
.msgLength
+= setupCsnTlv(&(hello
->csn
), confnum
);
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
,
175 mpls_inet_addr
*local
= NULL
, *remote
= NULL
;
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
) {
186 /* ldp-11 3.5.2. Hello Message */
187 if (hellotime
== 0) {
191 if (MPLS_LIST_HEAD(&e
->p
.iff
->addr_root
)) {
192 local
= &(MPLS_LIST_HEAD(&e
->p
.iff
->addr_root
)->address
);
194 local
= &g
->lsr_identifier
;
199 /* ldp-11 3.5.2. Hello Message */
200 if (hellotime
== 0) {
204 local
= &g
->lsr_identifier
;
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 */
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 */
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");
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
;
247 remote
= &a
->remote_source_address
;
250 switch (mpls_inet_addr_compare(local
, remote
)) {
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",
265 /* return FAILURE so we don't try to continue with the new adj */
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
);
281 LDP_PRINT(g
->user_data
,
282 "ldp_hello_process: exit(%d) configuration error\n", a
->index
);
285 ldp_session_shutdown(g
, a
->session
, MPLS_BOOL_TRUE
);
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");
294 LDP_EXIT(g
->user_data
, "ldp_hello_process");