Create a ldp_nexthop which mirrors the functionality of
[mpls-ldp-portable.git] / ldp / ldp_notif.c
blob3c8953c79592126eafe59197c8336c872716d69d
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 "ldp_struct.h"
11 #include "ldp_notif.h"
12 #include "ldp_attr.h"
13 #include "ldp_entity.h"
14 #include "ldp_mesg.h"
15 #include "ldp_pdu_setup.h"
16 #include "ldp_label_request.h"
17 #include "ldp_label_mapping.h"
18 #include "ldp_fec.h"
20 #include "mpls_trace_impl.h"
21 #include "mpls_timer_impl.h"
23 void ldp_notif_prepare_msg(ldp_mesg * msg, uint32_t msgid, ldp_attr * r_attr,
24 ldp_notif_status status)
26 mplsLdpNotifMsg_t *notif = NULL;
27 int error, forward = 0;
28 uint32_t msg_type = 0;
29 uint32_t msg_id = 0;
31 ldp_mesg_prepare(msg, MPLS_NOT_MSGTYPE, msgid);
32 notif = &msg->u.notif;
34 notif->statusTlvExists = 1;
36 /* we have to pass two more parameters one is F bit and other is E bit
37 E = 1 if it is a fatal error, 0 is for advisory notification
38 F = 1 then notification has to be forwarded. */
40 /* check to set the E bit */
41 if (status == LDP_NOTIF_SUCCESS ||
42 status == LDP_NOTIF_UNKNOWN_MESG ||
43 status == LDP_NOTIF_UNKNOWN_TVL ||
44 status == LDP_NOTIF_LOOP_DETECTED ||
45 status == LDP_NOTIF_UNKNOWN_FEC ||
46 status == LDP_NOTIF_NO_ROUTE ||
47 status == LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE ||
48 status == LDP_NOTIF_LABEL_RESOURCES_AVAILABLE ||
49 status == LDP_NOTIF_LABEL_ABORT ||
50 status == LDP_NOTIF_MISSING_MSG_PARAMS || status == LDP_NOTIF_UNSUPORTED_AF) {
51 error = 0;
52 } else {
53 error = 1;
56 /* check to set the F bit */
57 if (status == LDP_NOTIF_LOOP_DETECTED ||
58 status == LDP_NOTIF_UNKNOWN_FEC || status == LDP_NOTIF_NO_ROUTE) {
59 forward = 1;
60 } else {
61 forward = 0;
64 if (r_attr) {
65 switch (r_attr->state) {
66 case LDP_LSP_STATE_ABORT_RECV:
67 msg_type = MPLS_LBLABORT_MSGTYPE;
68 msg_id = r_attr->msg_id;
69 break;
70 default:
71 msg_type = 0;
74 notif->baseMsg.msgLength += setupStatusTlv(&notif->status, error, forward,
75 status, msg_id, msg_type);
77 /* We have to insert other tlv's like retpdu,extended status, returned
78 message
79 notif->exStatusTlvExists = 1;
80 notif->retPduTlvExists = 1;
84 mpls_return_enum ldp_notif_send(ldp_global * g, ldp_session * s,
85 ldp_attr * r_attr, ldp_notif_status status)
87 LDP_ENTER(g->user_data, "ldp_notif_send");
89 ldp_notif_prepare_msg(s->tx_message, g->message_identifier++, r_attr, status);
91 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
92 "Notification Sent(%d)\n", s->index);
94 if (ldp_mesg_send_tcp(g, s, s->tx_message) == MPLS_FAILURE) {
95 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
96 "Notification Send failed\n");
97 goto ldp_notif_send_error;
100 LDP_EXIT(g->user_data, "ldp_notif_send");
101 return MPLS_SUCCESS;
103 ldp_notif_send_error:
105 LDP_EXIT(g->user_data, "ldp_notif_send_error");
106 return MPLS_FAILURE;
109 void not2attr(mplsLdpNotifMsg_t * not, ldp_attr * attr, uint32_t flag)
111 attr->msg_id = not->baseMsg.msgId;
113 if (not->statusTlvExists && flag & LDP_ATTR_STATUS) {
114 memcpy(&attr->statusTlv, &not->status, sizeof(mplsLdpStatusTlv_t));
115 attr->statusTlvExists = 1;
117 if (not->lspidTlvExists && flag & LDP_ATTR_LSPID) {
118 memcpy(&attr->lspidTlv, &not->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
119 attr->lspidTlvExists = 1;
122 if (not->retMsgTlvExists && flag & LDP_ATTR_MSGID) {
123 memcpy(&attr->retMsgTlv, &not->retMsg, sizeof(mplsLdpLblMsgIdTlv_t));
124 attr->retMsgTlvExists = 1;
126 /* Attribute types are not defined in ldp_attr.h file need to
127 define these optional Tlv types */
129 /*if(not->exStatusTlvExists && flag & LDP_ATTR_HOPCOUNT) {
130 memcpy(&attr->exStatus,&not->exStatus,sizeof(mplsLdpHopTlv_t));
131 attr->exStatusTlvExists = 1;
133 if(not->retPduTlvExists && flag & LDP_ATTR_PATH) {
134 memcpy(&attr->retPdu,&not->retPdu,sizeof(mplsLdpPathTlv_t));
135 attr->retPduTlvExists = 1;
136 } */
139 mpls_return_enum ldp_notif_process(ldp_global * g, ldp_session * s,
140 ldp_adj * a, ldp_entity * e, ldp_attr * r_attr)
142 mpls_return_enum retval = MPLS_SUCCESS;
143 int status;
145 LDP_ENTER(g->user_data, "ldp_notif_process");
147 status = r_attr->statusTlv.flags.flags.status;
149 switch (status) {
150 case LDP_NOTIF_LABEL_ABORT:
151 retval = ldp_notif_label_request_aborted(g, s, r_attr);
152 break;
153 case LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE:
154 retval = ldp_notif_no_label_resources(g, s, r_attr);
155 break;
156 case LDP_NOTIF_NO_ROUTE:
157 case LDP_NOTIF_LOOP_DETECTED:
158 retval = ldp_notif_no_route(g, s, e, r_attr);
159 break;
160 case LDP_NOTIF_LABEL_RESOURCES_AVAILABLE:
161 retval = ldp_notif_label_resources_available(g, s, r_attr);
162 break;
163 case LDP_NOTIF_SUCCESS:
164 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SUCCESS:\n");
165 break;
166 case LDP_NOTIF_BAD_LDP_ID:
167 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_BAD_LDP_ID:\n");
168 break;
169 case LDP_NOTIF_BAD_PROTO:
170 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_BAD_PROTO:\n");
171 break;
172 case LDP_NOTIF_BAD_PDU_LEN:
173 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_BAD_PDU_LEN:\n");
174 break;
175 case LDP_NOTIF_UNKNOWN_MESG:
176 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_UNKNOWN_MESG:\n");
177 break;
178 case LDP_NOTIF_BAD_MESG_LEN:
179 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_BAD_MESG_LEN:\n");
180 break;
181 case LDP_NOTIF_UNKNOWN_TVL:
182 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_UNKNOWN_TVL:\n");
183 break;
184 case LDP_NOTIF_BAD_TLV_LEN:
185 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_BAD_TLV_LEN:\n");
186 break;
187 case LDP_NOTIF_MALFORMED_TLV:
188 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_MALFORMED_TLV:\n");
189 break;
190 case LDP_NOTIF_HOLD_TIMER_EXPIRED:
191 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_HOLD_TIMER_EXPIRED:\n");
192 break;
193 case LDP_NOTIF_SHUTDOWN:
194 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SHUTDOWN:\n");
195 break;
196 case LDP_NOTIF_UNKNOWN_FEC:
197 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_UNKNOWN_FEC:\n");
198 break;
199 case LDP_NOTIF_SESSION_REJECTED_NO_HELLO:
200 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SESSION_REJECTED_NO_HELLO:\n");
201 break;
202 case LDP_NOTIF_SESSION_REJECTED_PARAMETERS_ADVERTISEMENT_MODE:
203 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SESSION_REJECTED_PARAMETERS_ADVERTISEMENT_MODE:\n");
204 break;
205 case LDP_NOTIF_SESSION_REJECTED_PARAMETERS_MAX_PDU_LEN:
206 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SESSION_REJECTED_PARAMETERS_MAX_PDU_LEN:\n");
207 break;
208 case LDP_NOTIF_SESSION_REJECTED_PARAMETERS_LABEL_RANGE:
209 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SESSION_REJECTED_PARAMETERS_LABEL_RANGE:\n");
210 break;
211 case LDP_NOTIF_KEEPALIVE_TIMER_EXPIRED:
212 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_KEEPALIVE_TIMER_EXPIRED:\n");
213 break;
214 case LDP_NOTIF_MISSING_MSG_PARAMS:
215 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_MISSING_MSG_PARAMS:\n");
216 break;
217 case LDP_NOTIF_UNSUPORTED_AF:
218 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_UNSUPORTED_AF:\n");
219 break;
220 case LDP_NOTIF_SESSION_REJECTED_BAD_KEEPALIVE_TIME:
221 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_SESSION_REJECTED_BAD_KEEPALIVE_TIME:\n");
222 break;
223 case LDP_NOTIF_INTERNAL_ERROR:
224 LDP_TRACE_OUT(g->user_data, "LDP_NOTIF_INTERNAL_ERROR\n");
225 break;
226 default:
227 LDP_TRACE_OUT(g->user_data, "Receive an unknown notification: %08x\n",
228 status);
229 retval = MPLS_SUCCESS;
230 break;
233 LDP_EXIT(g->user_data, "ldp_notif_process");
234 return retval;
237 mpls_return_enum ldp_notif_label_request_aborted(ldp_global * g, ldp_session * s,
238 ldp_attr * r_attr)
240 ldp_attr *ds_attr = NULL;
242 LDP_ENTER(g->user_data, "ldp_notif_label_request_aborted");
244 ds_attr = MPLS_LIST_HEAD(&s->attr_root);
245 while (ds_attr != NULL) {
246 if (ds_attr->state == LDP_LSP_STATE_ABORT_SENT &&
247 ds_attr->msg_id == r_attr->msg_id) {
248 break;
250 ds_attr = MPLS_LIST_NEXT(&s->attr_root, ds_attr, _fs);
253 if (ds_attr) { /* LRqA.1 */
254 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* LRqA.2 */
256 LDP_EXIT(g->user_data, "ldp_notif_label_request_aborted");
257 return MPLS_SUCCESS;
260 LDP_EXIT(g->user_data, "ldp_notif_label_request_abort_error");
261 return MPLS_FAILURE;
264 mpls_return_enum ldp_notif_no_label_resources(ldp_global * g, ldp_session * s,
265 ldp_attr * s_attr)
267 ldp_attr_list *ds_list = NULL;
268 ldp_attr *ds_attr = NULL;
269 mpls_fec nfec;
271 LDP_ENTER(g->user_data, "ldp_notif_no_label_resources");
273 fec_tlv2mpls_fec(&s_attr->fecTlv, 0, &nfec);
274 /* NoRes.1 do not actually remove from tree, just change it's state */
276 if ((ds_list = ldp_attr_find_downstream_all(g, s, &nfec))) {
277 ds_attr = MPLS_LIST_HEAD(&s->attr_root);
278 while (ds_attr) {
279 if (ds_attr->state == LDP_LSP_STATE_REQ_SENT) {
280 ds_attr->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_RECV; /* NoRes.2 */
282 ds_attr = MPLS_LIST_NEXT(&s->attr_root, ds_attr, _fs);
286 s->no_label_resource_recv = MPLS_BOOL_TRUE; /* NoRes.3 */
288 LDP_EXIT(g->user_data, "ldp_notif_no_label_resource_error");
289 return MPLS_SUCCESS;
292 mpls_return_enum ldp_notif_no_route(ldp_global * g, ldp_session * s,
293 ldp_entity * e, ldp_attr * s_attr)
295 ldp_attr *ds_attr = NULL;
296 ldp_attr_list *ds_list = NULL;
297 mpls_fec nfec;
298 mpls_return_enum retval = MPLS_FAILURE;
300 LDP_ENTER(g->user_data, "ldp_notif_no_route\n");
302 fec_tlv2mpls_fec(&s_attr->fecTlv, 0, &nfec);
304 if ((ds_list = ldp_attr_find_downstream_all(g, s, &nfec))) {
305 ds_attr = MPLS_LIST_HEAD(&s->attr_root);
306 while (ds_attr) {
307 if (ds_attr->state == LDP_LSP_STATE_REQ_SENT) {
308 if (e->label_request_count) {
309 if (ds_attr->attempt_count < e->label_request_count) {
310 if (mpls_timer_handle_verify(g->timer_handle,
311 ds_attr->action_timer) == MPLS_BOOL_FALSE) {
312 ds_attr->action_timer =
313 mpls_timer_create(g->timer_handle, MPLS_UNIT_SEC,
314 s->cfg_label_request_timer, (void *)ds_attr, g,
315 ldp_attr_action_callback);
317 mpls_timer_start(g->timer_handle, ds_attr->action_timer,
318 MPLS_TIMER_ONESHOT);
320 retval = MPLS_SUCCESS;
321 } else {
322 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE);
323 retval = MPLS_FAILURE;
326 ds_attr = MPLS_LIST_NEXT(&s->attr_root, ds_attr, _fs);
330 LDP_EXIT(g->user_data, "ldp_notif_no_route\n");
331 return retval;
334 /* IV. Receive Notification/ Loop Detected */
336 /* Algo: Same as receive Notification/No Route */
338 mpls_return_enum ldp_notif_label_resources_available(ldp_global * g,
339 ldp_session * s, ldp_attr * r_attr)
341 ldp_attr *ds_attr = NULL;
342 ldp_session *nh_session = NULL;
343 mpls_fec nfec;
344 mpls_return_enum result;
346 LDP_ENTER(g->user_data, "ldp_notif_loop_detected\n");
348 s->no_label_resource_recv = MPLS_BOOL_FALSE; /* Res.1 */
350 ds_attr = MPLS_LIST_HEAD(&s->attr_root);
351 while (ds_attr != NULL) { /* Res.2 */
352 if (ds_attr->state == LDP_LSP_STATE_NO_LABEL_RESOURCE_RECV) {
353 fec_tlv2mpls_fec(&ds_attr->fecTlv, 0, &nfec);
355 result = ldp_get_next_hop_session_for_fec(g, &nfec, &nh_session);
356 switch (result) {
357 case MPLS_SUCCESS:
358 if (nh_session) {
359 if (nh_session->index == s->index) {
360 if (ldp_label_request_send(g, s, ds_attr, NULL) == MPLS_SUCCESS) { /* Res.4 */
361 continue;
365 case MPLS_FAILURE:
366 case MPLS_NO_ROUTE:
367 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* Res.5 */
368 break;
369 default:
370 MPLS_ASSERT(0);
373 ds_attr = MPLS_LIST_NEXT(&s->attr_root, ds_attr, _fs);
374 } /* Res.6 */
376 LDP_EXIT(g->user_data, "Notification label resources available");
377 return MPLS_SUCCESS;