Fixed next hop processing
[mpls-ldp-portable.git] / ldp / ldp_label_request.c
blobeece8a92f0aa6d51a8a54bb20d873442d6e61267
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_attr.h"
12 #include "ldp_fec.h"
13 #include "ldp_mesg.h"
14 #include "ldp_pdu_setup.h"
15 #include "ldp_notif.h"
16 #include "ldp_session.h"
17 #include "ldp_entity.h"
18 #include "ldp_label_mapping.h"
19 #include "ldp_label_request.h"
21 #include "mpls_timer_impl.h"
22 #include "mpls_policy_impl.h"
23 #include "mpls_tree_impl.h"
24 #include "mpls_trace_impl.h"
25 #include "mpls_fib_impl.h"
26 #include "mpls_lock_impl.h"
28 mpls_return_enum ldp_label_request_for_xc(ldp_global * g, ldp_session * s,
29 mpls_fec * fec, ldp_attr * us_attr, ldp_attr ** ds_attr)
32 LDP_ENTER(g->user_data, "ldp_label_request_for_xc");
34 if (!(*ds_attr)) {
35 if (!((*ds_attr) = ldp_attr_create(fec))) {
36 return MPLS_FATAL;
39 Prepare_Label_Request_Attributes(g, s, fec, (*ds_attr), us_attr);
40 (*ds_attr)->state = LDP_LSP_STATE_REQ_SENT;
41 if (ldp_label_request_send(g, s, us_attr, ds_attr) != MPLS_SUCCESS) {
42 return MPLS_FAILURE;
45 LDP_EXIT(g->user_data, "ldp_label_request_for_xc");
47 return MPLS_SUCCESS;
50 void ldp_label_request_prepare_msg(ldp_mesg * msg, uint32_t msgid,
51 ldp_attr * s_attr)
53 mplsLdpLblReqMsg_t *req = NULL;
54 int i;
56 ldp_mesg_prepare(msg, MPLS_LBLREQ_MSGTYPE, msgid);
57 req = &msg->u.request;
59 if (s_attr->fecTlvExists) {
60 req->fecTlvExists = 1;
61 req->baseMsg.msgLength += setupFecTlv(&req->fecTlv);
62 req->baseMsg.msgLength += addFecElem2FecTlv(&req->fecTlv,
63 &s_attr->fecTlv.fecElArray[0]);
65 if (s_attr->hopCountTlvExists) {
66 req->hopCountTlvExists = 1;
67 req->baseMsg.msgLength += setupHopCountTlv(&req->hopCountTlv,
68 s_attr->hopCountTlv.hcValue);
70 if (s_attr->pathVecTlvExists) {
71 req->pathVecTlvExists = 1;
72 req->baseMsg.msgLength += setupPathTlv(&req->pathVecTlv);
73 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) {
74 if (s_attr->pathVecTlv.lsrId[i]) {
75 req->baseMsg.msgLength += addLsrId2PathTlv(&req->pathVecTlv,
76 s_attr->pathVecTlv.lsrId[i]);
82 mpls_return_enum ldp_label_request_send(ldp_global * g, ldp_session * s,
83 ldp_attr * us_attr, ldp_attr ** ds_attr)
85 ldp_attr *ds_temp;
86 mpls_fec fec;
88 LDP_ENTER(g->user_data, "ldp_label_request_send");
89 MPLS_ASSERT(ds_attr && *ds_attr);
91 fec_tlv2mpls_fec(&((*ds_attr)->fecTlv), 0, &fec);
93 if ((ds_temp = ldp_attr_find_downstream_state(g, s, &fec,
94 LDP_LSP_STATE_REQ_SENT)) != NULL) { /* SLRq.1 */
96 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
97 "Label Request Send: request already pending(%d)\n", ds_temp->index);
99 ldp_attr_add_us2ds(us_attr, ds_temp);
101 /* we do not need the one passed in, but make sure that the caller
102 is using this one from here forth */
103 ldp_attr_remove_complete(g, *ds_attr, MPLS_BOOL_TRUE);
104 *ds_attr = ds_temp;
105 return MPLS_SUCCESS;
108 if (s->no_label_resource_recv == MPLS_BOOL_TRUE) { /* SLRq.2 */
109 goto ldp_label_request_send_error;
112 (*ds_attr)->msg_id = g->message_identifier++;
113 ldp_label_request_prepare_msg(s->tx_message, (*ds_attr)->msg_id, *ds_attr);
115 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
116 "Label Request Sent: session(%d)\n", s->index);
118 if (ldp_mesg_send_tcp(g, s, s->tx_message) == MPLS_FAILURE) { /* SLRq.3 */
119 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
120 "Label Request send failed\n");
121 goto ldp_label_request_send_error;
124 (*ds_attr)->state = LDP_LSP_STATE_REQ_SENT;
125 if (ldp_attr_insert_downstream(g, s, (*ds_attr)) == MPLS_FAILURE) { /* SLRq.4 */
126 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
127 "Couldn't insert sent attributes in tree\n");
128 goto ldp_label_request_send_error;
130 if (us_attr) {
131 ldp_attr_add_us2ds(us_attr, *ds_attr);
134 LDP_EXIT(g->user_data, "ldp_label_request_send");
136 return MPLS_SUCCESS; /* SLRq.5 */
138 ldp_label_request_send_error:
140 LDP_PRINT(g->user_data, "SLRq.6\n");
141 (*ds_attr)->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT;
142 ldp_attr_insert_downstream(g, s, (*ds_attr)); /* SLRq.6 */
144 LDP_EXIT(g->user_data, "ldp_label_request_send-error");
146 return MPLS_FAILURE; /* SLRq.7 */
149 void req2attr(mplsLdpLblReqMsg_t * req, ldp_attr * attr, uint32_t flag)
151 attr->msg_id = req->baseMsg.msgId;
153 if (req->fecTlvExists && flag & LDP_ATTR_FEC) {
154 memcpy(&attr->fecTlv, &req->fecTlv, sizeof(mplsLdpFecTlv_t));
155 attr->fecTlvExists = 1;
157 if (req->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) {
158 memcpy(&attr->hopCountTlv, &req->hopCountTlv, sizeof(mplsLdpHopTlv_t));
159 attr->hopCountTlvExists = 1;
161 if (req->pathVecTlvExists && flag & LDP_ATTR_PATH) {
162 memcpy(&attr->pathVecTlv, &req->pathVecTlv, sizeof(mplsLdpPathTlv_t));
163 attr->pathVecTlvExists = 1;
165 if (req->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) {
166 memcpy(&attr->lblMsgIdTlv, &req->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
167 attr->lblMsgIdTlvExists = 1;
169 if (req->lspidTlvExists && flag & LDP_ATTR_LSPID) {
170 memcpy(&attr->lspidTlv, &req->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
171 attr->lspidTlvExists = 1;
173 if (req->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) {
174 memcpy(&attr->trafficTlv, &req->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
175 attr->trafficTlvExists = 1;
179 void ldp_label_request_initial_callback(mpls_timer_handle timer, void *extra,
180 mpls_cfg_handle handle)
182 ldp_session *s = (ldp_session *) extra;
183 ldp_global *g = (ldp_global*)handle;
184 ldp_addr *nh_addr = NULL;
185 ldp_session *nh_session = NULL;
186 mpls_bool done = MPLS_BOOL_FALSE;
187 mpls_fec dest;
189 LDP_ENTER(g->user_data, "ldp_label_request_initial_callback");
191 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
192 "Initial Label Request Callback fired: session(%d)\n", s->index);
194 mpls_lock_get(g->global_lock);
196 mpls_timer_stop(g->timer_handle, timer);
198 if (mpls_fib_getfirst_route(g->fib_handle, &dest) == MPLS_SUCCESS) {
199 do {
201 ldp_fec *fnode = _ldp_attr_get_fec2(g, &dest, MPLS_BOOL_FALSE);
202 ldp_attr *attr = NULL;
203 ldp_fs *fs = NULL;
204 ldp_attr *ds_attr = NULL;
205 mpls_return_enum result;
207 /* check to see if export policy allows us to 'see' this route */
208 if (mpls_policy_export_check(g->user_data, &dest, &dest.nh)
209 == MPLS_BOOL_FALSE) {
210 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_DEBUG,
211 "Rejected by export policy\n");
212 continue;
215 /* find the next hop session corresponding to this FEC */
216 result = ldp_get_next_hop_session_for_fec(g,&dest,&nh_addr,&nh_session);
218 /* do we have a valid next hop session, and is the nexp hop session
219 * this session? */
220 if (result != MPLS_SUCCESS || nh_session->index != s->index) {
221 continue;
224 /* have we already sent a label request to this peer for this FEC? */
225 if (ldp_attr_find_downstream_state(g, s, &dest, LDP_LSP_STATE_REQ_SENT)) {
226 continue;
229 /* clear out info from the last FEC */
230 ds_attr = NULL;
232 /* jleu: duplicate code from ldp_attr_find_upstream_state_any */
233 fnode = _ldp_attr_get_fec2(g, &dest, MPLS_BOOL_FALSE);
234 if (!fnode) {
235 continue;
238 fs = MPLS_LIST_HEAD(&fnode->fs_root_us);
239 while (fs) {
240 attr = MPLS_LIST_HEAD(&fs->attr_root);
241 while (attr) {
242 if (attr->state == LDP_LSP_STATE_REQ_RECV ||
243 attr->state == LDP_LSP_STATE_MAP_SENT) {
244 if (!ds_attr) {
245 /* this is not neccessarily going to be XC'd to something */
246 ldp_label_request_for_xc(g, s, &dest, attr, &ds_attr);
249 attr = MPLS_LIST_NEXT(&fs->attr_root, attr, _fs);
251 fs = MPLS_LIST_NEXT(&fnode->fs_root_us, fs, _fec);
254 if (!ds_attr) {
256 * we did not find any received requests or sent mappings so
257 * send a request and xc it to nothing
259 ldp_label_request_for_xc(g, s, &dest, NULL, &ds_attr);
262 } while (mpls_fib_getnext_route(g->fib_handle, &dest) == MPLS_SUCCESS);
263 done = MPLS_BOOL_TRUE;
266 if (done == MPLS_BOOL_TRUE) {
267 mpls_timer_delete(g->timer_handle, timer);
268 MPLS_REFCNT_RELEASE(s, ldp_session_delete);
269 s->initial_distribution_timer = (mpls_timer_handle) 0;
270 } else {
271 mpls_timer_start(g->timer_handle, timer, MPLS_TIMER_ONESHOT);
272 /* need to mark the session with where it left off */
275 mpls_lock_release(g->global_lock);
277 LDP_EXIT(g->user_data, "ldp_label_request_initial_callback");
280 void Prepare_Label_Request_Attributes(ldp_global * g, ldp_session * s,
281 mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr)
283 int i;
285 MPLS_ASSERT(s && r_attr);
287 if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT ||
288 s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR ||
289 r_attr->hopCountTlvExists)) { /* PRqA.1 */
290 return;
293 /* is this LSR allowed to be an LER for FEC? *//* PRqA.2 */
294 /* some policy gunk needs to be checked here */
295 /* if not goto PRqA.6 */
297 s_attr->hopCountTlvExists = 1; /* PRqA.3 */
298 s_attr->hopCountTlv.hcValue = 1;
300 if (s->oper_loop_detection == LDP_LOOP_NONE) { /* PRqA.4 */
301 return;
304 if (g->label_merge == MPLS_BOOL_TRUE) { /* PRqA.5 */
305 return;
307 goto Prepare_Label_Request_Attributes_13;
309 if (r_attr && r_attr->hopCountTlvExists) { /* PRqA.6 */
310 s_attr->hopCountTlvExists = 1; /* PRqA.7 */
311 s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue) ?
312 (r_attr->hopCountTlv.hcValue + 1) : 0;
313 } else {
314 s_attr->hopCountTlvExists = 1; /* PRqA.8 */
315 s_attr->hopCountTlv.hcValue = 0;
318 if (s->oper_loop_detection == LDP_LOOP_NONE) { /* PRqA.9 */
319 return;
322 if (r_attr && r_attr->pathVecTlvExists) { /* PRqA.10 */
323 goto Prepare_Label_Request_Attributes_12;
326 if (g->label_merge == MPLS_BOOL_TRUE) { /* PRqA.11 */
327 return;
329 goto Prepare_Label_Request_Attributes_13;
331 Prepare_Label_Request_Attributes_12:
332 /* we only get to PRqA.12 if we have verified we have a r_attr */
333 s_attr->pathVecTlvExists = 1;
334 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
335 for (i = 1; i < (MPLS_MAXHOPSNUMBER - 1); i++) {
336 if (r_attr->pathVecTlv.lsrId[i - 1]) {
337 s_attr->pathVecTlv.lsrId[i] = r_attr->pathVecTlv.lsrId[i - 1];
340 return;
342 Prepare_Label_Request_Attributes_13:
343 s_attr->pathVecTlvExists = 1;
344 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
347 mpls_return_enum ldp_label_request_process(ldp_global * g, ldp_session * s,
348 ldp_adj * a, ldp_entity * e, ldp_attr * us_attr, mpls_fec * fec)
350 ldp_session *nh_session = NULL;
351 ldp_addr *nh_addr = NULL;
352 ldp_attr_list *us_list = NULL;
353 mpls_bool egress = MPLS_BOOL_FALSE;
354 ldp_attr *ds_attr = NULL;
355 ldp_attr *us_temp = NULL;
357 if (Check_Received_Attributes(g, s, us_attr, MPLS_LBLREQ_MSGTYPE) != MPLS_SUCCESS) { /* LRp.1 */
358 goto LRq_13;
361 switch (ldp_get_next_hop_session_for_fec(g, fec, &nh_addr, &nh_session)) {
362 case MPLS_SUCCESS: /* LRq.2 */
364 if (nh_addr == NULL) {
365 egress = MPLS_BOOL_TRUE;
367 if (nh_session != NULL && s->index == nh_session->index) { /* LRq.3 */
368 ldp_notif_send(g, s, us_attr, LDP_NOTIF_LOOP_DETECTED); /* LRq.4 */
369 goto LRq_13;
371 break;
373 case MPLS_FAILURE:
374 case MPLS_NO_ROUTE:
376 ldp_notif_send(g, s, us_attr, LDP_NOTIF_NO_ROUTE); /* LRq.5 */
377 goto LRq_13;
379 default:
381 MPLS_ASSERT(0);
385 if ((us_list = ldp_attr_find_upstream_all(g, s, fec)) != NULL) {
386 us_temp = MPLS_LIST_HEAD(us_list);
387 while (us_temp != NULL) {
388 if (us_temp->state == LDP_LSP_STATE_REQ_RECV && /* LRq.6 */
389 us_temp->msg_id == us_attr->msg_id) { /* LRq.7 */
390 goto LRq_13;
392 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
396 us_attr->state = LDP_LSP_STATE_REQ_RECV; /* LRq.8 */
398 if (ldp_attr_insert_upstream(g, s, us_attr) != MPLS_SUCCESS) {
399 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_ERROR,
400 "Couldn't insert recv attributes in tree\n");
401 goto ldp_label_request_process_error;
404 if (nh_session) {
405 ds_attr = ldp_attr_find_downstream_state(g, nh_session, fec,
406 LDP_LSP_STATE_MAP_RECV);
407 } else {
408 ds_attr = NULL;
411 if (g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) { /* LRq.9 */
412 if (ldp_label_mapping_with_xc(g, s, fec, &us_attr, ds_attr) != MPLS_SUCCESS) {
413 goto ldp_label_request_process_error;
416 if (egress == MPLS_BOOL_TRUE || ds_attr) {
417 goto LRq_11;
419 } else {
420 if ((!(egress == MPLS_BOOL_TRUE || ds_attr)) || (g->label_merge == MPLS_BOOL_FALSE)) {
421 goto LRq_10;
424 if (ldp_label_mapping_with_xc(g, s, fec, &us_attr, ds_attr) != MPLS_SUCCESS) {
425 goto ldp_label_request_process_error;
427 goto LRq_11;
430 LRq_10:
431 ds_attr = NULL;
432 if (ldp_label_request_for_xc(g, nh_session, fec, us_attr, &ds_attr) !=
433 MPLS_SUCCESS) {
434 goto ldp_label_request_process_error;
437 LRq_11:
438 /* the work done by LRq_11 is handled in ldp_label_mapping_with_xc() */
439 LRq_13:
440 if (ds_attr != NULL && ds_attr->in_tree == MPLS_BOOL_FALSE) {
441 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE);
443 return MPLS_SUCCESS;
445 ldp_label_request_process_error:
446 return MPLS_FAILURE;