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
10 #include "ldp_struct.h"
11 #include "ldp_session.h"
15 #include "ldp_notif.h"
16 #include "ldp_entity.h"
17 #include "ldp_inlabel.h"
18 #include "ldp_outlabel.h"
19 #include "ldp_nexthop.h"
20 #include "ldp_global.h"
21 #include "ldp_pdu_setup.h"
22 #include "ldp_label_rel_with.h"
23 #include "ldp_label_mapping.h"
24 #include "ldp_label_request.h"
26 #include "mpls_timer_impl.h"
27 #include "mpls_fib_impl.h"
28 #include "mpls_lock_impl.h"
29 #include "mpls_tree_impl.h"
30 #include "mpls_trace_impl.h"
31 #include "mpls_mm_impl.h"
32 #include "mpls_policy_impl.h"
37 #include "mpls_mpls_impl.h"
40 mpls_return_enum
ldp_label_mapping_with_xc(ldp_global
* g
, ldp_session
* s
,
41 ldp_fec
* f
, ldp_attr
** us_attr
, ldp_attr
* ds_attr
)
43 mpls_return_enum result
;
44 mpls_bool propogating
= MPLS_BOOL_TRUE
;
45 mpls_bool egress
= MPLS_BOOL_TRUE
;
50 if (!((*us_attr
) = ldp_attr_create(&f
->info
))) {
55 propogating
= MPLS_BOOL_FALSE
;
56 egress
= MPLS_BOOL_TRUE
;
59 Prepare_Label_Mapping_Attributes(g
, s
, &f
->info
, ds_attr
, (*us_attr
),
60 propogating
, MPLS_BOOL_TRUE
, egress
);
62 if (ldp_attr_insert_upstream2(g
, s
, (*us_attr
), f
) != MPLS_SUCCESS
) {
63 ldp_attr_delete(*us_attr
);
67 if (ldp_label_mapping_send(g
, s
, (*us_attr
), ds_attr
) != MPLS_SUCCESS
) {
68 ldp_attr_delete(*us_attr
);
72 if (ds_attr
&& ds_attr
->outlabel
) {
74 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
75 LDP_TRACE_FLAG_BINDING
, "Cross Connect Added\n");
77 result
= ldp_inlabel_add_outlabel(g
,(*us_attr
)->inlabel
,ds_attr
->outlabel
);
78 if (result
!= MPLS_SUCCESS
) {
79 ldp_label_withdraw_send(g
, s
, (*us_attr
), LDP_NOTIF_NONE
);
86 ldp_session
*ldp_get_next_hop_session_for_fec2(ldp_fec
* f
, ldp_nexthop
*nh
) {
87 ldp_session
*session
= NULL
;
89 * find the info about the next hop for this FEC
91 if (nh
->addr
&& nh
->addr
->session_root
.count
> 0) {
92 session
= mpls_link_list_head_data(&nh
->addr
->session_root
);
93 } else if (nh
->iff
&& nh
->iff
->is_p2p
== MPLS_BOOL_TRUE
&&
95 ldp_adj
*adj
= MPLS_LIST_HEAD(&nh
->iff
->entity
->adj_root
);
96 session
= adj
? adj
->session
: NULL
;
101 mpls_return_enum
ldp_get_next_hop_session_for_fec(ldp_global
* g
,
102 mpls_fec
* fec
, mpls_nexthop
*nh
, ldp_session
** next_hop_session
)
105 ldp_nexthop
*n
= NULL
;
107 MPLS_ASSERT(next_hop_session
);
109 if (!(f
= ldp_fec_find(g
, fec
))) {
110 return MPLS_NO_ROUTE
;
113 if (!(n
= ldp_fec_nexthop_find(f
, nh
))) {
114 return MPLS_NO_ROUTE
;
117 *next_hop_session
= ldp_get_next_hop_session_for_fec2(f
,n
);
118 return (*next_hop_session
) ? MPLS_SUCCESS
: MPLS_FAILURE
;
121 mpls_return_enum
Check_Received_Attributes(ldp_global
* g
, ldp_session
* s
,
122 ldp_attr
* r_attr
, uint16_t type
)
127 if (!r_attr
->hopCountTlvExists
) { /* CRa.1 */
128 goto Check_Received_Attributes_5
;
131 if (r_attr
->hopCountTlv
.hcValue
>= s
->cfg_hop_count_limit
) { /* CRa.2 */
132 LDP_PRINT(g
->user_data
, "CRa.2\n");
133 goto Check_Received_Attributes_6
;
136 if (!r_attr
->pathVecTlvExists
) { /* CRa.3 */
137 goto Check_Received_Attributes_5
;
140 for (i
= 0; i
< MPLS_MAXHOPSNUMBER
; i
++) { /* CRa.4 */
141 if (r_attr
->pathVecTlv
.lsrId
[i
]) {
143 if (r_attr
->pathVecTlv
.lsrId
[i
] == g
->lsr_identifier
.u
.ipv4
) {
144 goto Check_Received_Attributes_6
;
145 LDP_PRINT(g
->user_data
, "CRa.4a\n");
147 if (count
> s
->oper_path_vector_limit
) {
148 goto Check_Received_Attributes_6
;
149 LDP_PRINT(g
->user_data
, "CRa.4b\n");
154 Check_Received_Attributes_5
:
157 Check_Received_Attributes_6
:
158 if (type
!= MPLS_LBLMAP_MSGTYPE
) {
159 ldp_notif_send(g
, s
, r_attr
, LDP_NOTIF_LOOP_DETECTED
); /* CRa.7 */
161 return MPLS_FAILURE
; /* CRa.8 */
164 void Prepare_Label_Mapping_Attributes(ldp_global
* g
, ldp_session
* s
,
165 mpls_fec
* fec
, ldp_attr
* r_attr
, ldp_attr
* s_attr
, mpls_bool propogating
,
166 mpls_bool already
, mpls_bool egress
)
171 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
172 /* this function uses goto quite extensivly for a REASON!! */
173 /* Check Appedix A of the LDP draft */
175 LDP_ENTER(g
->user_data
, "Prepare_Label_Mapping_Attributes");
178 memset(&dummy
, 0, sizeof(ldp_attr
));
179 mpls_fec2fec_tlv(fec
, &dummy
.fecTlv
, 0);
180 dummy
.fecTlvExists
= 1;
181 dummy
.fecTlv
.numberFecElements
= 1;
185 if (!(s
->oper_loop_detection
== LDP_LOOP_HOPCOUNT
||
186 s
->oper_loop_detection
== LDP_LOOP_HOPCOUNT_PATHVECTOR
||
187 r_attr
->hopCountTlvExists
)) { /* PMpA.1 */
188 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
192 if (egress
) {/* PMpA.2 */
193 /* I'm egress (for now) */
194 s_attr
->hopCountTlvExists
= 1;
195 s_attr
->hopCountTlv
.hcValue
= 1; /* PMpA.3 */
196 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
200 if (!(r_attr
->hopCountTlvExists
)) { /* PMpA.4 */
201 goto Prepare_Label_Mapping_Attributes_8
;
204 if (!(g
->ttl_less_domain
== MPLS_BOOL_TRUE
&&
205 s
->cfg_remote_in_ttl_less_domain
== MPLS_BOOL_TRUE
)) { /* PMpA.5 */
206 goto Prepare_Label_Mapping_Attributes_7
;
209 s_attr
->hopCountTlvExists
= 1;
210 s_attr
->hopCountTlv
.hcValue
= 1; /* PMpA.6 */
211 goto Prepare_Label_Mapping_Attributes_9
;
213 Prepare_Label_Mapping_Attributes_7
:
214 s_attr
->hopCountTlvExists
= 1;
215 s_attr
->hopCountTlv
.hcValue
= (r_attr
->hopCountTlv
.hcValue
) ?
216 (r_attr
->hopCountTlv
.hcValue
+ 1) : 0;
217 goto Prepare_Label_Mapping_Attributes_9
;
219 Prepare_Label_Mapping_Attributes_8
:
220 s_attr
->hopCountTlvExists
= 1;
221 s_attr
->hopCountTlv
.hcValue
= 0;
223 Prepare_Label_Mapping_Attributes_9
:
224 if (s
->oper_loop_detection
== LDP_LOOP_NONE
) {
225 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
229 if (r_attr
->pathVecTlvExists
) { /* PMpA.10 */
230 goto Prepare_Label_Mapping_Attributes_19
;
233 if (propogating
== MPLS_BOOL_FALSE
) { /* PMpA.11 */
234 goto Prepare_Label_Mapping_Attributes_20
;
237 if (g
->label_merge
!= MPLS_BOOL_TRUE
) { /* PMpA.12 */
238 goto Prepare_Label_Mapping_Attributes_14
;
241 if (already
== MPLS_BOOL_FALSE
) { /* PMpA.13 */
242 goto Prepare_Label_Mapping_Attributes_20
;
245 Prepare_Label_Mapping_Attributes_14
:
246 if (!r_attr
->hopCountTlvExists
) {
247 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
251 if (r_attr
->hopCountTlv
.hcValue
== 0) { /* PMpA.15 */
252 goto Prepare_Label_Mapping_Attributes_20
;
255 if (already
== MPLS_BOOL_FALSE
) { /* PMpA.16 */
256 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
260 /* r_attr contain PrevHopCount _IF_ we had one */
261 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
262 return; /* PMpA.17 */
264 if (r_attr
->hopCountTlv
.hcValue
!= 0) { /* PMpA.18 */
265 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
269 Prepare_Label_Mapping_Attributes_19
:
270 s_attr
->pathVecTlvExists
= 1;
271 s_attr
->pathVecTlv
.lsrId
[0] = g
->lsr_identifier
.u
.ipv4
;
272 for (i
= 1; i
< (MPLS_MAXHOPSNUMBER
- 1); i
++) {
273 if (r_attr
->pathVecTlv
.lsrId
[i
- 1]) {
274 s_attr
->pathVecTlv
.lsrId
[0] = r_attr
->pathVecTlv
.lsrId
[i
- 1];
278 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
281 Prepare_Label_Mapping_Attributes_20
:
282 s_attr
->pathVecTlvExists
= 1;
283 s_attr
->pathVecTlv
.lsrId
[0] = g
->lsr_identifier
.u
.ipv4
;
285 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
289 void map2attr(mplsLdpLblMapMsg_t
* map
, ldp_attr
* attr
, uint32_t flag
)
291 attr
->msg_id
= map
->baseMsg
.msgId
;
293 if (map
->fecTlvExists
&& flag
& LDP_ATTR_FEC
) {
294 memcpy(&attr
->fecTlv
, &map
->fecTlv
, sizeof(mplsLdpFecTlv_t
));
295 attr
->fecTlvExists
= 1;
297 if (map
->genLblTlvExists
&& flag
& LDP_ATTR_LABEL
) {
298 memcpy(&attr
->genLblTlv
, &map
->genLblTlv
, sizeof(mplsLdpGenLblTlv_t
));
299 attr
->genLblTlvExists
= 1;
300 } else if (map
->atmLblTlvExists
&& flag
& LDP_ATTR_LABEL
) {
301 memcpy(&attr
->atmLblTlv
, &map
->atmLblTlv
, sizeof(mplsLdpAtmLblTlv_t
));
302 attr
->atmLblTlvExists
= 1;
303 } else if (map
->frLblTlvExists
&& flag
& LDP_ATTR_LABEL
) {
304 memcpy(&attr
->frLblTlv
, &map
->frLblTlv
, sizeof(mplsLdpFrLblTlv_t
));
305 attr
->frLblTlvExists
= 1;
307 if (map
->hopCountTlvExists
&& flag
& LDP_ATTR_HOPCOUNT
) {
308 memcpy(&attr
->hopCountTlv
, &map
->hopCountTlv
, sizeof(mplsLdpHopTlv_t
));
309 attr
->hopCountTlvExists
= 1;
311 if (map
->pathVecTlvExists
&& flag
& LDP_ATTR_PATH
) {
312 memcpy(&attr
->pathVecTlv
, &map
->pathVecTlv
, sizeof(mplsLdpPathTlv_t
));
313 attr
->pathVecTlvExists
= 1;
315 if (map
->lblMsgIdTlvExists
&& flag
& LDP_ATTR_MSGID
) {
316 memcpy(&attr
->lblMsgIdTlv
, &map
->lblMsgIdTlv
, sizeof(mplsLdpLblMsgIdTlv_t
));
317 attr
->lblMsgIdTlvExists
= 1;
319 if (map
->lspidTlvExists
&& flag
& LDP_ATTR_LSPID
) {
320 memcpy(&attr
->lspidTlv
, &map
->lspidTlv
, sizeof(mplsLdpLspIdTlv_t
));
321 attr
->lspidTlvExists
= 1;
323 if (map
->trafficTlvExists
&& flag
& LDP_ATTR_TRAFFIC
) {
324 memcpy(&attr
->trafficTlv
, &map
->trafficTlv
, sizeof(mplsLdpTrafficTlv_t
));
325 attr
->trafficTlvExists
= 1;
329 void attr2map(ldp_attr
* attr
, mplsLdpLblMapMsg_t
* map
)
331 if (attr
->fecTlvExists
) {
332 memcpy(&map
->fecTlv
, &attr
->fecTlv
, sizeof(mplsLdpFecTlv_t
));
333 map
->fecTlvExists
= 1;
335 if (attr
->genLblTlvExists
) {
336 memcpy(&map
->genLblTlv
, &attr
->genLblTlv
, sizeof(mplsLdpGenLblTlv_t
));
337 map
->genLblTlvExists
= 1;
339 if (attr
->atmLblTlvExists
) {
340 memcpy(&map
->atmLblTlv
, &attr
->atmLblTlv
, sizeof(mplsLdpAtmLblTlv_t
));
341 map
->atmLblTlvExists
= 1;
343 if (attr
->frLblTlvExists
) {
344 memcpy(&map
->frLblTlv
, &attr
->frLblTlv
, sizeof(mplsLdpFrLblTlv_t
));
345 map
->frLblTlvExists
= 1;
347 if (attr
->hopCountTlvExists
) {
348 memcpy(&map
->hopCountTlv
, &attr
->hopCountTlv
, sizeof(mplsLdpHopTlv_t
));
349 map
->hopCountTlvExists
= 1;
351 if (attr
->pathVecTlvExists
) {
352 memcpy(&map
->pathVecTlv
, &attr
->pathVecTlv
, sizeof(mplsLdpPathTlv_t
));
353 map
->pathVecTlvExists
= 1;
355 if (attr
->lblMsgIdTlvExists
) {
356 memcpy(&map
->lblMsgIdTlv
, &attr
->lblMsgIdTlv
, sizeof(mplsLdpLblMsgIdTlv_t
));
357 map
->lblMsgIdTlvExists
= 1;
359 if (attr
->lspidTlvExists
) {
360 memcpy(&map
->lspidTlv
, &attr
->lspidTlv
, sizeof(mplsLdpLspIdTlv_t
));
361 map
->lspidTlvExists
= 1;
363 if (attr
->trafficTlvExists
) {
364 memcpy(&map
->trafficTlv
, &attr
->trafficTlv
, sizeof(mplsLdpTrafficTlv_t
));
365 map
->trafficTlvExists
= 1;
369 void ldp_label_mapping_initial_callback(mpls_timer_handle timer
, void *extra
,
370 mpls_cfg_handle handle
)
372 ldp_session
*s
= (ldp_session
*) extra
;
373 ldp_global
*g
= (ldp_global
*)handle
;
374 ldp_attr
*ds_attr
= NULL
;
375 ldp_attr
*us_attr
= NULL
;
376 ldp_session
*nh_session
= NULL
;
377 mpls_bool done
= MPLS_BOOL_FALSE
;
381 LDP_ENTER(g
->user_data
, "ldp_label_mapping_initial_callback");
383 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_TIMER
,
384 "Initial Label Mapping fired: session(%d)\n", s
->index
);
386 mpls_lock_get(g
->global_lock
);
388 mpls_timer_stop(g
->timer_handle
, timer
);
390 if ((f
= MPLS_LIST_HEAD(&g
->fec
))) {
392 if ((nh
= MPLS_LIST_HEAD(&f
->nh_root
))) {
394 switch (f
->info
.type
) {
395 case MPLS_FEC_PREFIX
:
396 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
397 LDP_TRACE_FLAG_ROUTE
, "Processing prefix FEC: %08x/%d ",
398 f
->info
.u
.prefix
.network
.u
.ipv4
, f
->info
.u
.prefix
.length
);
401 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
402 LDP_TRACE_FLAG_ROUTE
, "Processing host FEC: %08x ",
403 f
->info
.u
.host
.u
.ipv4
);
406 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
407 LDP_TRACE_FLAG_ROUTE
, "Processingu L2CC FEC: %d %d %d ",
408 f
->info
.u
.l2cc
.connection_id
, f
->info
.u
.l2cc
.group_id
,
409 f
->info
.u
.l2cc
.type
);
415 if (nh
->type
& MPLS_NH_IP
) {
416 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
417 LDP_TRACE_FLAG_ROUTE
, "via %08x\n", nh
->addr
->address
.u
.ipv4
);
419 if (nh
->type
& MPLS_NH_IF
) {
420 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
421 LDP_TRACE_FLAG_ROUTE
, "via %s\n", nh
->iff
->name
);
424 /* are we allowed to export this route from the rib */
425 if (mpls_policy_export_check(g
->user_data
, &f
->info
, &nh
->info
) ==
427 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
428 LDP_TRACE_FLAG_POLICY
, "Rejected by export policy\n");
432 /* have we already sent a mapping for this fec to the new session? */
433 if ((us_attr
= ldp_attr_find_upstream_state2(g
, s
, f
,
434 LDP_LSP_STATE_MAP_SENT
))) {
435 /* no need to sent another mapping */
436 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
437 LDP_TRACE_FLAG_ROUTE
, "Already sent this FEC to session %d\n",
442 if (!(nh_session
= ldp_get_next_hop_session_for_fec2(f
,nh
))) {
445 if (nh_session
->index
== s
->index
) {
446 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
447 LDP_TRACE_FLAG_ROUTE
, "Nexthop session(%d) == session(%d)\n",
448 nh_session
->index
, s
->index
);
451 ds_attr
= ldp_attr_find_downstream_state2(g
, nh_session
, f
,
452 LDP_LSP_STATE_MAP_RECV
);
455 if ((g
->label_merge
!= MPLS_BOOL_TRUE
) &&
456 ldp_attr_num_us2ds(ds_attr
)) {
457 /* we have a ds label, but can't use it */
463 /* we can use it, merge on baby */
464 ldp_label_mapping_with_xc(g
, s
, f
, &us_attr
, ds_attr
);
466 /* we don't have a ds label */
468 /* we will be egress? */
469 if (g
->lsp_control_mode
== LDP_CONTROL_ORDERED
) {
470 if (mpls_policy_egress_check(g
->user_data
, &f
->info
,
471 &nh
->info
) == MPLS_BOOL_TRUE
) {
472 ldp_label_mapping_with_xc(g
, s
, f
, &us_attr
, NULL
);
475 ldp_label_mapping_with_xc(g
, s
, f
, &us_attr
, NULL
);
478 } while ((nh
= MPLS_LIST_NEXT(&f
->nh_root
, nh
, _fec
)));
480 } while ((f
= MPLS_LIST_NEXT(&g
->fec
, f
, _global
)));
481 done
= MPLS_BOOL_TRUE
;
484 done
= MPLS_BOOL_TRUE
;
486 if (done
== MPLS_BOOL_TRUE
) {
487 mpls_timer_delete(g
->timer_handle
, timer
);
488 MPLS_REFCNT_RELEASE(s
, ldp_session_delete
);
489 s
->initial_distribution_timer
= (mpls_timer_handle
) 0;
491 mpls_timer_start(g
->timer_handle
, timer
, MPLS_TIMER_ONESHOT
);
492 /* need to mark the session with where it left off */
495 mpls_lock_release(g
->global_lock
);
497 LDP_EXIT(g
->user_data
, "ldp_label_mapping_initial_callback");
500 mpls_return_enum
ldp_label_mapping_send(ldp_global
* g
, ldp_session
* s
,
501 ldp_attr
* us_attr
, ldp_attr
* ds_attr
)
503 ldp_inlabel
*in
= NULL
;
506 LDP_ENTER(g
->user_data
, "ldp_label_mapping_send");
507 MPLS_ASSERT(us_attr
);
509 if ((in
= ldp_inlabel_create_complete(g
, s
, us_attr
)) == NULL
) { /* SL.1-3 */
513 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
516 us_attr
->state
= LDP_LSP_STATE_MAP_SENT
;
518 us_attr
->msg_id
= g
->message_identifier
;
519 ldp_label_mapping_prepare_msg(s
->tx_message
, g
->message_identifier
++,
522 if (ldp_mesg_send_tcp(g
, s
, s
->tx_message
) != MPLS_SUCCESS
) { /* SL.4 */
523 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_SEND
, LDP_TRACE_FLAG_ERROR
,
524 "Failed sending Label Mapping to %s\n",
526 goto ldp_label_mapping_send_error
;
529 ldp_attr_add_us2ds(us_attr
, ds_attr
);
531 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_SEND
, LDP_TRACE_FLAG_LABEL
,
532 "Label Mapping Sent to %s for %08x/%d\n",
534 us_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
535 us_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
);
537 us_attr
->state
= LDP_LSP_STATE_MAP_SENT
; /* SL.6,7 */
539 LDP_EXIT(g
->user_data
, "ldp_label_mapping_send");
540 return MPLS_SUCCESS
; /* SL.8 */
543 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_STATE
,
544 "No Label Resources\n");
546 while ((us_temp
= ldp_attr_find_upstream_state2(g
, s
, us_attr
->fec
,
547 LDP_LSP_STATE_REQ_RECV
)) != NULL
) { /* SL.9 */
548 ldp_notif_send(g
, s
, us_temp
, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE
);
550 s
->no_label_resource_sent
= MPLS_BOOL_TRUE
; /* SL.12 */
551 us_temp
->state
= LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT
; /* SL.13 */
554 LDP_EXIT(g
->user_data
, "ldp_label_mapping_send");
558 ldp_label_mapping_send_error
:
560 LDP_EXIT(g
->user_data
, "ldp_label_mapping_send-error");
564 void ldp_label_mapping_prepare_msg(ldp_mesg
* msg
, uint32_t msgid
,
567 mplsLdpLblMapMsg_t
*map
= NULL
;
572 ldp_mesg_prepare(msg
, MPLS_LBLMAP_MSGTYPE
, msgid
);
575 if (s_attr
->fecTlvExists
) {
576 /* JLEU: only 1 FEC is allowed!! */
577 map
->fecTlvExists
= 1;
578 map
->baseMsg
.msgLength
+= setupFecTlv(&map
->fecTlv
);
579 map
->baseMsg
.msgLength
+= addFecElem2FecTlv(&map
->fecTlv
,
580 &s_attr
->fecTlv
.fecElArray
[0]);
582 if (s_attr
->genLblTlvExists
) {
583 map
->genLblTlvExists
= 1;
584 map
->baseMsg
.msgLength
+= setupGenLblTlv(&map
->genLblTlv
,
585 s_attr
->genLblTlv
.label
);
587 if (s_attr
->atmLblTlvExists
) {
588 map
->atmLblTlvExists
= 1;
589 map
->baseMsg
.msgLength
+= setupAtmLblTlv(&map
->atmLblTlv
, 0, 0,
590 s_attr
->atmLblTlv
.flags
.flags
.vpi
, s_attr
->atmLblTlv
.vci
);
592 if (s_attr
->frLblTlvExists
) {
593 map
->frLblTlvExists
= 1;
594 map
->baseMsg
.msgLength
+= setupFrLblTlv(&map
->frLblTlv
, 0,
595 s_attr
->frLblTlv
.flags
.flags
.len
, s_attr
->frLblTlv
.flags
.flags
.dlci
);
597 if (s_attr
->hopCountTlvExists
) {
598 map
->hopCountTlvExists
= 1;
599 map
->baseMsg
.msgLength
+= setupHopCountTlv(&map
->hopCountTlv
,
600 s_attr
->hopCountTlv
.hcValue
);
602 if (s_attr
->pathVecTlvExists
) {
603 map
->pathVecTlvExists
= 1;
604 map
->baseMsg
.msgLength
+= setupPathTlv(&map
->pathVecTlv
);
605 for (i
= 0; i
< MPLS_MAXHOPSNUMBER
; i
++) {
606 if (s_attr
->pathVecTlv
.lsrId
[i
]) {
607 map
->baseMsg
.msgLength
+= addLsrId2PathTlv(&map
->pathVecTlv
,
608 s_attr
->pathVecTlv
.lsrId
[i
]);
613 if (s_attr
->lblMsgIdTlvExists
) {
615 if (s_attr
->lspidTlvExists
) {
617 if (s_attr
->trafficTlvExists
) {
622 mpls_return_enum
ldp_label_mapping_process(ldp_global
* g
, ldp_session
* s
,
623 ldp_adj
* a
, ldp_entity
* e
, ldp_attr
* r_attr
, ldp_fec
* f
)
625 mpls_return_enum retval
= MPLS_SUCCESS
;
626 ldp_session
*peer
= NULL
;
627 ldp_attr_list
*us_list
= NULL
;
628 ldp_attr_list
*ds_list
= NULL
;
629 ldp_attr
*ds_attr
= NULL
;
630 ldp_attr
*ds_temp
= NULL
;
631 ldp_attr
*us_attr
= NULL
;
632 ldp_attr
*us_temp
= NULL
;
634 ldp_nexthop
*nh
= NULL
;
636 ldp_outlabel
*out
= NULL
;
637 mpls_bool requested
= MPLS_BOOL_FALSE
;
638 ldp_attr
*update
= NULL
;
639 mpls_bool need_request
= MPLS_BOOL_FALSE
;
641 LDP_ENTER(g
->user_data
, "ldp_label_mapping_process");
643 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
, LDP_TRACE_FLAG_LABEL
,
644 "Label Mapping Recv from %s for %08x/%d\n",
646 r_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
647 r_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
);
649 if ((ds_attr
= ldp_attr_find_downstream_state2(g
, s
, f
,
650 LDP_LSP_STATE_REQ_SENT
)) != NULL
) { /* LMp.1 */
651 /* just remove the req from the tree, we will use the r_attr sent to us */
652 ldp_attr_delete_downstream(g
, s
, ds_attr
);
653 requested
= MPLS_BOOL_TRUE
;
655 requested
= MPLS_BOOL_FALSE
;
659 ds_attr
->state
= LDP_LSP_STATE_MAP_RECV
; /* LMp.2 */
662 * ds_attr is the mapping we will keep and is NOT in the tree, unless
663 * it is an update mapping ...
665 if (Check_Received_Attributes(g
, s
, ds_attr
, MPLS_LBLMAP_MSGTYPE
) ==
666 MPLS_SUCCESS
) { /* LMp.3 */
671 * A loop was detected
673 if ((ds_list
= ldp_attr_find_downstream_all2(g
, s
, f
))) {
674 ds_temp
= MPLS_LIST_HEAD(ds_list
);
676 * check all the labels this session has received from "s" for "fec"
677 * do we have a duplicat?
680 if ((ds_temp
->state
== LDP_LSP_STATE_MAP_RECV
) && /* LMp.4 */
681 ldp_attr_is_equal(ds_temp
, ds_attr
, LDP_ATTR_LABEL
) == /* LMp.5 */
683 /* remove record of the label and remove it switching */
684 ldp_attr_remove_complete(g
, ds_temp
, MPLS_BOOL_TRUE
); /* LMp.6,7 */
686 * I think this is supposed to be 32 NOT 33, we need to release
691 ds_temp
= MPLS_LIST_NEXT(ds_list
, ds_temp
, _fs
);
695 LDP_PRINT(g
->user_data
, "Receive_Label_Map_8: send release");
696 if (ldp_label_release_send(g
, s
, ds_attr
, LDP_NOTIF_LOOP_DETECTED
) !=
697 MPLS_SUCCESS
) { /* LMp.8 */
698 retval
= MPLS_FAILURE
;
706 ds_temp
= ldp_attr_find_downstream_state2(g
, s
, f
, LDP_LSP_STATE_MAP_RECV
);
707 if (requested
== MPLS_BOOL_TRUE
||
708 g
->label_merge
== MPLS_BOOL_FALSE
|| !ds_temp
) {
709 /* !merging then this is always a new LSP
710 * merging w/o a recv'd mapping is a new LSP
711 * this check comes from Note 6
716 /* searching all recv'd attrs for matched mappings,
717 * stop after finding 1st match
719 if ((ds_list
= ldp_attr_find_downstream_all2(g
, s
, f
))) {
720 ds_temp
= MPLS_LIST_HEAD(ds_list
);
722 if (ds_temp
->state
== LDP_LSP_STATE_MAP_RECV
) { /* LMp.9 */
723 if (ldp_attr_is_equal(ds_attr
, ds_temp
, LDP_ATTR_LABEL
) ==
724 MPLS_BOOL_TRUE
) { /* LMp.10 */
726 * this mapping matches an existing mapping, but it
727 * could contain updated attributes
733 * we have been given another label for the same FEC and we
734 * didn't request it, release it
736 LDP_PRINT(g
->user_data
, "LMp.10 dup without req\n");
740 ds_temp
= MPLS_LIST_NEXT(ds_list
, ds_temp
, _fs
);
746 * update ONLY has a value for updated label mapping
749 nh
= ldp_nexthop_for_fec_session(f
,s
);
752 * the following departs from the procedure, it allows for filtering
755 * Are we configured to accept and INSTALL this mapping?
757 if (mpls_policy_import_check(g
->user_data
, &f
->info
, &nh
->info
) ==
760 * policy has rejected it, store it away
763 ldp_attr2ldp_attr(ds_attr
, update
, LDP_ATTR_HOPCOUNT
| LDP_ATTR_PATH
|
764 LDP_ATTR_MSGID
| LDP_ATTR_LSPID
| LDP_ATTR_TRAFFIC
);
765 /* JLEU free ds_attr? */
766 update
->filtered
= MPLS_BOOL_TRUE
;
767 if (update
->outlabel
&& update
->outlabel
->switching
== MPLS_BOOL_TRUE
) {
768 /* the mapping has been filtered, but the original wasn't? */
772 ds_attr
->filtered
= MPLS_BOOL_TRUE
;
773 if (ldp_attr_insert_downstream(g
, s
, ds_attr
) != MPLS_SUCCESS
) {
774 retval
= MPLS_FAILURE
;
783 * if we don't know about the route, or we don't have a next hop session,
784 * or the next hop session isn't the one who sent us the mapping ....
786 if (g
->label_retention_mode
== LDP_RETENTION_CONSERVATIVE
) { /* LMp.13C */
787 LDP_PRINT(g
->user_data
, "LMp.13C conservative\n");
794 LDP_PRINT(g
->user_data
, "index: %3d %08x/%d %d\n", ds_attr
->index
,
795 ds_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
796 ds_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
, ds_attr
->state
);
799 ldp_attr2ldp_attr(ds_attr
, update
, LDP_ATTR_HOPCOUNT
| LDP_ATTR_PATH
|
800 LDP_ATTR_MSGID
| LDP_ATTR_LSPID
| LDP_ATTR_TRAFFIC
);
801 /* JLEU free ds_attr? */
804 if (ldp_attr_insert_downstream(g
, s
, ds_attr
) != MPLS_SUCCESS
) {
805 retval
= MPLS_FAILURE
;
812 * this is slightly different form the procedure, we can still be
813 * transit for a FEC we are not configured to be ingress for.
814 * Either way we only need to do the "install for fwd/switching"
815 * only once. We could arrive here multiple times due to updates,
816 * only install it the first time
818 if ((!update
) || (!update
->outlabel
)) {
820 * we haven't installed it yet.
821 * Either new (!update), or a result of a "Detect FEC Nexthop Change"
822 * and we had this mapping in our database (!update->outlabel))
825 if (!(out
= ldp_outlabel_create_complete(g
, s
, ds_attr
, nh
))) {
826 LDP_PRINT(g
->user_data
, "LMp.15 failure creating outlabel\n");
830 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
831 "Out Label Added\n");
835 * are we configured to act as ingress for this FEC?
837 if (mpls_policy_ingress_check(g
->user_data
, &f
->info
, &nh
->info
) ==
838 MPLS_BOOL_TRUE
) { /* LMp.14 */
840 * yep, bind the label to the FEC
842 if (ds_attr
->ingress
!= MPLS_BOOL_TRUE
) {
845 ftn
.outsegment_index
= ds_attr
->outlabel
->info
.handle
;
846 memcpy(&ftn
.fec
, &f
->info
, sizeof(mpls_fec
));
847 lsr_cfg_ftn_set2(g
->lsr_handle
, &ftn
, LSR_CFG_ADD
|LSR_FTN_CFG_FEC
|
848 LSR_FTN_CFG_OUTSEGMENT
);
850 mpls_mpls_fec2out_add(g
->mpls_handle
, &f
->info
, &ds_attr
->outlabel
->info
);
852 ds_attr
->ingress
= MPLS_BOOL_TRUE
;
853 ds_attr
->outlabel
->merge_count
++;
854 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
855 "FEC Binding Added\n");
859 /* create a set of attrs that we will fill and compare against
860 * if this mapping were to be propogate these are the attrs it would have
861 * by comparing what we did sent in the past to these, we con figure out
862 * if we need to send an updated mapping
864 memset(&dumb_attr
, 0, sizeof(ldp_attr
));
865 mpls_fec2fec_tlv(&f
->info
, &dumb_attr
.fecTlv
, 0);
866 dumb_attr
.fecTlvExists
= 1;
867 dumb_attr
.fecTlv
.numberFecElements
= 1;
870 * by definition (we received a label mapping that will be used) this
871 * LSR is _not_ the egress, so calculate a hop and path based on the
872 * mapping we received. We will compare this with mapping that have
873 * already been sent. If they differ, we will send an updated mapping
875 Prepare_Label_Mapping_Attributes(g
, s
, &f
->info
, ds_attr
, &dumb_attr
,
876 MPLS_BOOL_TRUE
, MPLS_BOOL_TRUE
, MPLS_BOOL_FALSE
);
880 * this is the first time we've seen this mapping, add it to the database.
881 * all future updates will modify this entry in place
884 if (ldp_attr_insert_downstream(g
, s
, ds_attr
) != MPLS_SUCCESS
) {
885 retval
= MPLS_FAILURE
;
893 * this is an update, propogate update to all member of this LSP
895 us_temp
= MPLS_LIST_HEAD(&ds_attr
->us_attr_root
);
897 us_temp
= MPLS_LIST_NEXT(&ds_attr
->us_attr_root
, us_temp
, _ds_attr
);
902 peer
= MPLS_LIST_HEAD(&g
->session
);
903 while (peer
) { /* LMp.17 */
905 if (peer
->state
!= LDP_STATE_OPERATIONAL
||
906 peer
->index
== s
->index
) {
907 /* peer equals msg source */
911 /* check to see if a upstream mapping has been xc'd to this
912 * downstream mapping for this session. If so we need to propogate
913 * the attr changes (if any)
915 us_temp
= MPLS_LIST_HEAD(&ds_attr
->us_attr_root
);
917 if (us_temp
->session
->index
== peer
->index
) {
920 us_temp
= MPLS_LIST_NEXT(&ds_attr
->us_attr_root
, us_temp
, _ds_attr
);
923 if (us_temp
) { /* LMp.18 */
925 if ((us_list
= ldp_attr_find_upstream_all2(g
, peer
, f
))) {
926 us_temp
= MPLS_LIST_HEAD(us_list
);
928 if (us_temp
->state
== LDP_LSP_STATE_MAP_SENT
) {
930 if (ldp_attr_is_equal(us_temp
, &dumb_attr
,
931 LDP_ATTR_HOPCOUNT
| LDP_ATTR_PATH
) != MPLS_BOOL_TRUE
) {
932 if (ldp_label_mapping_with_xc(g
, us_temp
->session
, f
, &us_temp
,
933 ds_attr
) != MPLS_SUCCESS
) { /* LMp.24-26 */
934 retval
= MPLS_FAILURE
;
939 us_temp
= MPLS_LIST_NEXT(us_list
, us_temp
, _fs
);
944 if ((peer
->oper_distribution_mode
== LDP_DISTRIBUTION_UNSOLICITED
) &&
945 (g
->lsp_control_mode
== LDP_CONTROL_ORDERED
)) { /* LMp.19 */
948 * if we're not merging and we have multiple ORDERED DU sessions,
949 * we will to start requesting labels after we propogate the mapping to
952 if (need_request
== MPLS_BOOL_TRUE
) {
953 if (ldp_attr_find_downstream_state2(g
, peer
, f
,
954 LDP_LSP_STATE_REQ_SENT
) == NULL
) {
956 * we don't have a request for FEC to peer outstanding, make one
959 if (ldp_label_request_for_xc(g
, peer
, &f
->info
, NULL
, &ds_temp
) !=
961 retval
= MPLS_FAILURE
;
967 * We're in DU more, either we're merging, or we're not merging and
968 * this is the first peer we're propogating this mapping to
972 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_attr
, ds_attr
) !=
974 retval
= MPLS_FAILURE
;
978 * if we're not merging, we will need to request a label for
981 if (g
->label_merge
== MPLS_BOOL_FALSE
) {
982 need_request
= MPLS_BOOL_TRUE
;
988 while ((us_temp
= ldp_attr_find_upstream_state2(g
, peer
, f
,
989 LDP_LSP_STATE_REQ_RECV
))) {
991 if (peer
->oper_distribution_mode
== LDP_DISTRIBUTION_UNSOLICITED
) {
992 if (need_request
== MPLS_BOOL_TRUE
) {
993 if (ldp_attr_find_downstream_state2(g
, peer
, f
,
994 LDP_LSP_STATE_REQ_SENT
) == NULL
) {
996 * we don't have a request for FEC to peer outstanding
999 if (ldp_label_request_for_xc(g
, peer
, &f
->info
, us_temp
,
1000 &ds_temp
) != MPLS_SUCCESS
) {
1001 retval
= MPLS_FAILURE
;
1006 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_temp
,
1007 ds_attr
) != MPLS_SUCCESS
) {
1008 retval
= MPLS_FAILURE
;
1013 if ((us_list
= ldp_attr_find_upstream_all2(g
, peer
, f
))) {
1014 us_temp
= MPLS_LIST_HEAD(ds_list
);
1016 if (us_temp
->state
== LDP_LSP_STATE_REQ_RECV
) {
1017 if (need_request
== MPLS_BOOL_TRUE
) {
1018 if (ldp_attr_find_downstream_state2(g
, peer
, f
,
1019 LDP_LSP_STATE_REQ_SENT
) == NULL
) {
1021 * we don't have a request for FEC to peer outstanding
1024 if (ldp_label_request_for_xc(g
, peer
, &f
->info
, us_temp
,
1025 &ds_temp
) != MPLS_SUCCESS
) {
1026 retval
= MPLS_FAILURE
;
1031 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_temp
,
1032 ds_attr
) != MPLS_SUCCESS
) {
1033 retval
= MPLS_FAILURE
;
1037 * if we're not merging, we will need to request a label for
1040 if (g
->label_merge
== MPLS_BOOL_FALSE
) {
1041 need_request
= MPLS_BOOL_TRUE
;
1045 us_temp
= MPLS_LIST_NEXT(us_list
, us_temp
, _fs
);
1052 peer
= MPLS_LIST_NEXT(&g
->session
, peer
, _global
);
1056 LDP_EXIT(g
->user_data
, "ldp_label_mapping_process");
1060 LDP_PRINT(g
->user_data
, "Receive_Label_Map_32: send release");
1061 if (ldp_label_release_send(g
, s
, ds_attr
, LDP_NOTIF_NONE
) != MPLS_SUCCESS
) {
1062 retval
= MPLS_FAILURE
;
1064 LDP_EXIT(g
->user_data
, "ldp_label_mapping_process");