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
= MPLS_SUCCESS
;
44 mpls_bool propogating
= MPLS_BOOL_TRUE
;
45 mpls_bool egress
= MPLS_BOOL_FALSE
;
46 mpls_bool egress_flag
= MPLS_BOOL_FALSE
;
47 mpls_bool created
= MPLS_BOOL_FALSE
;
52 nh
= MPLS_LIST_HEAD(&f
->nh_root
);
54 if (egress_flag
== MPLS_BOOL_FALSE
) {
55 egress_flag
= mpls_policy_egress_check(g
->user_data
, &f
->info
, &nh
->info
);
57 nh
= MPLS_LIST_NEXT(&f
->nh_root
, nh
, _fec
);
61 if (!((*us_attr
) = ldp_attr_create(g
, &f
->info
))) {
64 MPLS_REFCNT_HOLD((*us_attr
));
65 created
= MPLS_BOOL_TRUE
;
67 if ((!ds_attr
) && (egress_flag
== MPLS_BOOL_TRUE
)) {
68 propogating
= MPLS_BOOL_FALSE
;
69 egress
= MPLS_BOOL_TRUE
;
72 Prepare_Label_Mapping_Attributes(g
, s
, &f
->info
, ds_attr
, (*us_attr
),
73 propogating
, MPLS_BOOL_TRUE
, egress
);
75 result
= ldp_label_mapping_send(g
, s
, f
, (*us_attr
), ds_attr
);
76 if (result
!= MPLS_SUCCESS
) {
77 if (created
== MPLS_BOOL_TRUE
) {
78 /* this should result in it being deleted, since we're
79 * the only one who should be holding a ref
81 MPLS_REFCNT_RELEASE2(g
, (*us_attr
), ldp_attr_delete
);
86 if (created
== MPLS_BOOL_TRUE
) {
87 result
= ldp_attr_insert_upstream2(g
, s
, (*us_attr
), f
);
88 /* now that it is in the tree (supposedly) we can safely
89 * release our ref, if it is not in the tree, then this should
90 * result in it beig deleted
92 MPLS_REFCNT_RELEASE2(g
, (*us_attr
), ldp_attr_delete
);
93 if (result
!= MPLS_SUCCESS
) {
99 * If we have a downstream mapping (not neccessarily installed) and
100 * the downstream and upstream session are not the same....
102 if (ds_attr
&& ((*us_attr
)->session
->index
!= ds_attr
->session
->index
)) {
103 /* then link the attra */
104 ldp_attr_add_us2ds((*us_attr
), ds_attr
);
106 /* if we just created the upstream, and we have install the
107 * downstream, then cross connect them */
108 if ((created
== MPLS_BOOL_TRUE
) && ds_attr
->outlabel
) {
110 if ((*us_attr
)->inlabel
->outlabel
) {
112 * if we use an existing upstream mapping (in ldp_label_mapping_send())
113 * the inlabel will already be be connected to an outlabel;
115 MPLS_ASSERT((*us_attr
)->inlabel
->outlabel
== ds_attr
->outlabel
);
117 LDP_TRACE_LOG(g
->user_data
,MPLS_TRACE_STATE_ALL
,LDP_TRACE_FLAG_BINDING
,
118 "Cross Connect Added for %08x/%d from %s -> %s\n",
119 f
->info
.u
.prefix
.network
.u
.ipv4
, f
->info
.u
.prefix
.length
,
120 (*us_attr
)->session
->session_name
, ds_attr
->session
->session_name
);
122 result
= ldp_inlabel_add_outlabel(g
,(*us_attr
)->inlabel
,
124 if (result
!= MPLS_SUCCESS
) {
133 ldp_session
*ldp_get_next_hop_session_for_fec2(ldp_fec
* f
, ldp_nexthop
*nh
) {
134 ldp_session
*session
= NULL
;
136 * find the info about the next hop for this FEC
138 if (nh
->addr
&& nh
->addr
->session
) {
139 session
= nh
->addr
->session
;
140 } else if (nh
->iff
&& nh
->iff
->is_p2p
== MPLS_BOOL_TRUE
&&
142 ldp_adj
*adj
= MPLS_LIST_HEAD(&nh
->iff
->entity
->adj_root
);
143 session
= adj
? adj
->session
: NULL
;
148 mpls_return_enum
ldp_get_next_hop_session_for_fec(ldp_global
* g
,
149 mpls_fec
* fec
, mpls_nexthop
*nh
, ldp_session
** next_hop_session
)
152 ldp_nexthop
*n
= NULL
;
154 MPLS_ASSERT(next_hop_session
);
156 if (!(f
= ldp_fec_find(g
, fec
))) {
157 return MPLS_NO_ROUTE
;
160 if (!(n
= ldp_fec_nexthop_find(f
, nh
))) {
161 return MPLS_NO_ROUTE
;
164 *next_hop_session
= ldp_get_next_hop_session_for_fec2(f
,n
);
165 return (*next_hop_session
) ? MPLS_SUCCESS
: MPLS_FAILURE
;
168 mpls_return_enum
Check_Received_Attributes(ldp_global
* g
, ldp_session
* s
,
169 ldp_attr
* r_attr
, uint16_t type
)
174 if (!r_attr
->hopCountTlvExists
) { /* CRa.1 */
175 goto Check_Received_Attributes_5
;
178 if (r_attr
->hopCountTlv
.hcValue
>= s
->cfg_hop_count_limit
) { /* CRa.2 */
179 LDP_PRINT(g
->user_data
, "CRa.2\n");
180 goto Check_Received_Attributes_6
;
183 if (!r_attr
->pathVecTlvExists
) { /* CRa.3 */
184 goto Check_Received_Attributes_5
;
187 for (i
= 0; i
< MPLS_MAXHOPSNUMBER
; i
++) { /* CRa.4 */
188 if (r_attr
->pathVecTlv
.lsrId
[i
]) {
190 if (r_attr
->pathVecTlv
.lsrId
[i
] == g
->lsr_identifier
.u
.ipv4
) {
191 goto Check_Received_Attributes_6
;
192 LDP_PRINT(g
->user_data
, "CRa.4a\n");
194 if (count
> s
->oper_path_vector_limit
) {
195 goto Check_Received_Attributes_6
;
196 LDP_PRINT(g
->user_data
, "CRa.4b\n");
201 Check_Received_Attributes_5
:
204 Check_Received_Attributes_6
:
205 if (type
!= MPLS_LBLMAP_MSGTYPE
) {
206 ldp_notif_send(g
, s
, r_attr
, LDP_NOTIF_LOOP_DETECTED
); /* CRa.7 */
208 return MPLS_FAILURE
; /* CRa.8 */
211 void Prepare_Label_Mapping_Attributes(ldp_global
* g
, ldp_session
* s
,
212 mpls_fec
* fec
, ldp_attr
* r_attr
, ldp_attr
* s_attr
, mpls_bool propogating
,
213 mpls_bool already
, mpls_bool egress
)
218 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
219 /* this function uses goto quite extensivly for a REASON!! */
220 /* Check Appedix A of the LDP draft */
222 LDP_ENTER(g
->user_data
, "Prepare_Label_Mapping_Attributes");
225 memset(&dummy
, 0, sizeof(ldp_attr
));
226 mpls_fec2fec_tlv(fec
, &dummy
.fecTlv
, 0);
227 dummy
.fecTlvExists
= 1;
228 dummy
.fecTlv
.numberFecElements
= 1;
232 if (!(s
->oper_loop_detection
== LDP_LOOP_HOPCOUNT
||
233 s
->oper_loop_detection
== LDP_LOOP_HOPCOUNT_PATHVECTOR
||
234 r_attr
->hopCountTlvExists
)) { /* PMpA.1 */
235 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
239 if (egress
) {/* PMpA.2 */
240 /* I'm egress (for now) */
241 s_attr
->hopCountTlvExists
= 1;
242 s_attr
->hopCountTlv
.hcValue
= 1; /* PMpA.3 */
243 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
247 if (!(r_attr
->hopCountTlvExists
)) { /* PMpA.4 */
248 goto Prepare_Label_Mapping_Attributes_8
;
251 if (!(g
->ttl_less_domain
== MPLS_BOOL_TRUE
&&
252 s
->cfg_remote_in_ttl_less_domain
== MPLS_BOOL_TRUE
)) { /* PMpA.5 */
253 goto Prepare_Label_Mapping_Attributes_7
;
256 s_attr
->hopCountTlvExists
= 1;
257 s_attr
->hopCountTlv
.hcValue
= 1; /* PMpA.6 */
258 goto Prepare_Label_Mapping_Attributes_9
;
260 Prepare_Label_Mapping_Attributes_7
:
261 s_attr
->hopCountTlvExists
= 1;
262 s_attr
->hopCountTlv
.hcValue
= (r_attr
->hopCountTlv
.hcValue
) ?
263 (r_attr
->hopCountTlv
.hcValue
+ 1) : 0;
264 goto Prepare_Label_Mapping_Attributes_9
;
266 Prepare_Label_Mapping_Attributes_8
:
267 s_attr
->hopCountTlvExists
= 1;
268 s_attr
->hopCountTlv
.hcValue
= 0;
270 Prepare_Label_Mapping_Attributes_9
:
271 if (s
->oper_loop_detection
== LDP_LOOP_NONE
) {
272 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
276 if (r_attr
->pathVecTlvExists
) { /* PMpA.10 */
277 goto Prepare_Label_Mapping_Attributes_19
;
280 if (propogating
== MPLS_BOOL_FALSE
) { /* PMpA.11 */
281 goto Prepare_Label_Mapping_Attributes_20
;
284 if (g
->label_merge
!= MPLS_BOOL_TRUE
) { /* PMpA.12 */
285 goto Prepare_Label_Mapping_Attributes_14
;
288 if (already
== MPLS_BOOL_FALSE
) { /* PMpA.13 */
289 goto Prepare_Label_Mapping_Attributes_20
;
292 Prepare_Label_Mapping_Attributes_14
:
293 if (!r_attr
->hopCountTlvExists
) {
294 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
298 if (r_attr
->hopCountTlv
.hcValue
== 0) { /* PMpA.15 */
299 goto Prepare_Label_Mapping_Attributes_20
;
302 if (already
== MPLS_BOOL_FALSE
) { /* PMpA.16 */
303 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
307 /* r_attr contain PrevHopCount _IF_ we had one */
308 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
309 return; /* PMpA.17 */
311 if (r_attr
->hopCountTlv
.hcValue
!= 0) { /* PMpA.18 */
312 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
316 Prepare_Label_Mapping_Attributes_19
:
317 s_attr
->pathVecTlvExists
= 1;
318 s_attr
->pathVecTlv
.lsrId
[0] = g
->lsr_identifier
.u
.ipv4
;
319 for (i
= 1; i
< (MPLS_MAXHOPSNUMBER
- 1); i
++) {
320 if (r_attr
->pathVecTlv
.lsrId
[i
- 1]) {
321 s_attr
->pathVecTlv
.lsrId
[0] = r_attr
->pathVecTlv
.lsrId
[i
- 1];
325 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
328 Prepare_Label_Mapping_Attributes_20
:
329 s_attr
->pathVecTlvExists
= 1;
330 s_attr
->pathVecTlv
.lsrId
[0] = g
->lsr_identifier
.u
.ipv4
;
332 LDP_EXIT(g
->user_data
, "Prepare_Label_Mapping_Attributes");
336 void map2attr(mplsLdpLblMapMsg_t
* map
, ldp_attr
* attr
, uint32_t flag
)
338 attr
->msg_id
= map
->baseMsg
.msgId
;
340 if (map
->fecTlvExists
&& flag
& LDP_ATTR_FEC
) {
341 memcpy(&attr
->fecTlv
, &map
->fecTlv
, sizeof(mplsLdpFecTlv_t
));
342 attr
->fecTlvExists
= 1;
344 if (map
->genLblTlvExists
&& flag
& LDP_ATTR_LABEL
) {
345 memcpy(&attr
->genLblTlv
, &map
->genLblTlv
, sizeof(mplsLdpGenLblTlv_t
));
346 attr
->genLblTlvExists
= 1;
347 } else if (map
->atmLblTlvExists
&& flag
& LDP_ATTR_LABEL
) {
348 memcpy(&attr
->atmLblTlv
, &map
->atmLblTlv
, sizeof(mplsLdpAtmLblTlv_t
));
349 attr
->atmLblTlvExists
= 1;
350 } else if (map
->frLblTlvExists
&& flag
& LDP_ATTR_LABEL
) {
351 memcpy(&attr
->frLblTlv
, &map
->frLblTlv
, sizeof(mplsLdpFrLblTlv_t
));
352 attr
->frLblTlvExists
= 1;
354 if (map
->hopCountTlvExists
&& flag
& LDP_ATTR_HOPCOUNT
) {
355 memcpy(&attr
->hopCountTlv
, &map
->hopCountTlv
, sizeof(mplsLdpHopTlv_t
));
356 attr
->hopCountTlvExists
= 1;
358 if (map
->pathVecTlvExists
&& flag
& LDP_ATTR_PATH
) {
359 memcpy(&attr
->pathVecTlv
, &map
->pathVecTlv
, sizeof(mplsLdpPathTlv_t
));
360 attr
->pathVecTlvExists
= 1;
362 if (map
->lblMsgIdTlvExists
&& flag
& LDP_ATTR_MSGID
) {
363 memcpy(&attr
->lblMsgIdTlv
, &map
->lblMsgIdTlv
, sizeof(mplsLdpLblMsgIdTlv_t
));
364 attr
->lblMsgIdTlvExists
= 1;
366 if (map
->lspidTlvExists
&& flag
& LDP_ATTR_LSPID
) {
367 memcpy(&attr
->lspidTlv
, &map
->lspidTlv
, sizeof(mplsLdpLspIdTlv_t
));
368 attr
->lspidTlvExists
= 1;
370 if (map
->trafficTlvExists
&& flag
& LDP_ATTR_TRAFFIC
) {
371 memcpy(&attr
->trafficTlv
, &map
->trafficTlv
, sizeof(mplsLdpTrafficTlv_t
));
372 attr
->trafficTlvExists
= 1;
376 void attr2map(ldp_attr
* attr
, mplsLdpLblMapMsg_t
* map
)
378 if (attr
->fecTlvExists
) {
379 memcpy(&map
->fecTlv
, &attr
->fecTlv
, sizeof(mplsLdpFecTlv_t
));
380 map
->fecTlvExists
= 1;
382 if (attr
->genLblTlvExists
) {
383 memcpy(&map
->genLblTlv
, &attr
->genLblTlv
, sizeof(mplsLdpGenLblTlv_t
));
384 map
->genLblTlvExists
= 1;
386 if (attr
->atmLblTlvExists
) {
387 memcpy(&map
->atmLblTlv
, &attr
->atmLblTlv
, sizeof(mplsLdpAtmLblTlv_t
));
388 map
->atmLblTlvExists
= 1;
390 if (attr
->frLblTlvExists
) {
391 memcpy(&map
->frLblTlv
, &attr
->frLblTlv
, sizeof(mplsLdpFrLblTlv_t
));
392 map
->frLblTlvExists
= 1;
394 if (attr
->hopCountTlvExists
) {
395 memcpy(&map
->hopCountTlv
, &attr
->hopCountTlv
, sizeof(mplsLdpHopTlv_t
));
396 map
->hopCountTlvExists
= 1;
398 if (attr
->pathVecTlvExists
) {
399 memcpy(&map
->pathVecTlv
, &attr
->pathVecTlv
, sizeof(mplsLdpPathTlv_t
));
400 map
->pathVecTlvExists
= 1;
402 if (attr
->lblMsgIdTlvExists
) {
403 memcpy(&map
->lblMsgIdTlv
, &attr
->lblMsgIdTlv
, sizeof(mplsLdpLblMsgIdTlv_t
));
404 map
->lblMsgIdTlvExists
= 1;
406 if (attr
->lspidTlvExists
) {
407 memcpy(&map
->lspidTlv
, &attr
->lspidTlv
, sizeof(mplsLdpLspIdTlv_t
));
408 map
->lspidTlvExists
= 1;
410 if (attr
->trafficTlvExists
) {
411 memcpy(&map
->trafficTlv
, &attr
->trafficTlv
, sizeof(mplsLdpTrafficTlv_t
));
412 map
->trafficTlvExists
= 1;
416 void ldp_label_mapping_initial_callback(mpls_timer_handle timer
, void *extra
,
417 mpls_cfg_handle handle
)
419 ldp_session
*s
= (ldp_session
*) extra
;
420 ldp_global
*g
= (ldp_global
*)handle
;
421 ldp_attr
*ds_attr
= NULL
;
422 ldp_attr
*us_attr
= NULL
;
423 ldp_session
*nh_session
= NULL
;
424 mpls_bool done
= MPLS_BOOL_FALSE
;
428 LDP_ENTER(g
->user_data
, "ldp_label_mapping_initial_callback");
430 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_TIMER
,
431 "Initial Label Mapping fired: session(%d)\n", s
->index
);
433 mpls_lock_get(g
->global_lock
);
435 mpls_timer_stop(g
->timer_handle
, timer
);
437 f
= MPLS_LIST_HEAD(&g
->fec
);
439 nh
= MPLS_LIST_HEAD(&f
->nh_root
);
441 switch (f
->info
.type
) {
442 case MPLS_FEC_PREFIX
:
443 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
444 LDP_TRACE_FLAG_ROUTE
, "Processing prefix FEC: %08x/%d ",
445 f
->info
.u
.prefix
.network
.u
.ipv4
, f
->info
.u
.prefix
.length
);
448 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
449 LDP_TRACE_FLAG_ROUTE
, "Processing host FEC: %08x ",
450 f
->info
.u
.host
.u
.ipv4
);
453 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
454 LDP_TRACE_FLAG_ROUTE
, "Processingu L2CC FEC: %d %d %d ",
455 f
->info
.u
.l2cc
.connection_id
, f
->info
.u
.l2cc
.group_id
,
456 f
->info
.u
.l2cc
.type
);
462 if (nh
->info
.type
& MPLS_NH_IP
) {
463 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
464 LDP_TRACE_FLAG_ROUTE
, "via %08x\n", nh
->addr
->address
.u
.ipv4
);
466 if (nh
->info
.type
& MPLS_NH_IF
&& nh
->iff
) {
467 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
468 LDP_TRACE_FLAG_ROUTE
, "via %p\n", nh
->iff
->handle
);
471 /* are we allowed to export this route from the rib */
472 if (mpls_policy_export_check(g
->user_data
, &f
->info
, &nh
->info
) ==
474 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
475 LDP_TRACE_FLAG_POLICY
, "Rejected by export policy\n");
476 goto ldp_label_mapping_initial_callback_end_nh
;
479 /* have we already sent a mapping for this fec to the new session? */
480 if ((us_attr
= ldp_attr_find_upstream_state2(g
, s
, f
,
481 LDP_LSP_STATE_MAP_SENT
))) {
482 /* no need to sent another mapping */
483 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
484 LDP_TRACE_FLAG_ROUTE
, "Already sent this FEC to session %d\n",
486 goto ldp_label_mapping_initial_callback_end_nh
;
489 if (!(nh_session
= ldp_get_next_hop_session_for_fec2(f
,nh
))) {
492 if (nh_session
->index
== s
->index
) {
493 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
,
494 LDP_TRACE_FLAG_ROUTE
, "Nexthop session(%d) == session(%d)\n",
495 nh_session
->index
, s
->index
);
496 goto ldp_label_mapping_initial_callback_end_nh
;
498 ds_attr
= ldp_attr_find_downstream_state2(g
, nh_session
, f
,
499 LDP_LSP_STATE_MAP_RECV
);
502 if ((g
->label_merge
!= MPLS_BOOL_TRUE
) &&
503 ldp_attr_num_us2ds(ds_attr
)) {
504 /* we have a ds label, but can't use it */
510 /* we can use it, merge on baby */
511 ldp_label_mapping_with_xc(g
, s
, f
, &us_attr
, ds_attr
);
513 /* we don't have a ds label */
515 /* we will be egress? */
516 if (g
->lsp_control_mode
== LDP_CONTROL_ORDERED
) {
517 if (mpls_policy_egress_check(g
->user_data
, &f
->info
,
518 &nh
->info
) == MPLS_BOOL_TRUE
) {
519 ldp_label_mapping_with_xc(g
, s
, f
, &us_attr
, NULL
);
522 ldp_label_mapping_with_xc(g
, s
, f
, &us_attr
, NULL
);
525 ldp_label_mapping_initial_callback_end_nh
:
526 nh
= MPLS_LIST_NEXT(&f
->nh_root
, nh
, _fec
);
528 f
= MPLS_LIST_NEXT(&g
->fec
, f
, _global
);
530 done
= MPLS_BOOL_TRUE
;
532 if (done
== MPLS_BOOL_TRUE
) {
533 mpls_timer_delete(g
->timer_handle
, timer
);
534 MPLS_REFCNT_RELEASE(s
, ldp_session_delete
);
535 s
->initial_distribution_timer
= (mpls_timer_handle
) 0;
537 mpls_timer_start(g
->timer_handle
, timer
, MPLS_TIMER_ONESHOT
);
538 /* need to mark the session with where it left off */
541 mpls_lock_release(g
->global_lock
);
543 LDP_EXIT(g
->user_data
, "ldp_label_mapping_initial_callback");
546 mpls_return_enum
ldp_label_mapping_send(ldp_global
* g
, ldp_session
* s
,
547 ldp_fec
*f
, ldp_attr
* us_attr
, ldp_attr
* ds_attr
)
549 ldp_inlabel
*in
= NULL
;
550 ldp_attr
*us_temp
, *existing
= NULL
;
552 LDP_ENTER(g
->user_data
, "ldp_label_mapping_send");
553 MPLS_ASSERT(us_attr
);
557 * before we can enable this, inlabels need to keep track of all of
558 * the attr that link to it. Then when running in DU independent mode we
559 * can correctly attach the us and ds attrs involved when propogating a
560 * new mapping for a FEC we've already distributed labels for
562 existing
= ldp_attr_find_upstream_map_in_labelspace(f
, s
->cfg_label_space
);
566 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
567 "Using an existing label\n");
568 in
= existing
->inlabel
;
569 ldp_attr_add_inlabel(g
, us_attr
, in
);
571 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
572 "Generating a label\n");
573 in
= ldp_inlabel_create_complete(g
, s
, us_attr
);
576 if (!in
) { /* SL.1-3 */
580 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
583 us_attr
->state
= LDP_LSP_STATE_MAP_SENT
;
585 us_attr
->msg_id
= g
->message_identifier
;
586 ldp_label_mapping_prepare_msg(s
->tx_message
, g
->message_identifier
++,
589 if (ldp_mesg_send_tcp(g
, s
, s
->tx_message
) != MPLS_SUCCESS
) { /* SL.4 */
590 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_SEND
, LDP_TRACE_FLAG_ERROR
,
591 "Failed sending Label Mapping to %s\n",
593 goto ldp_label_mapping_send_error
;
596 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_SEND
, LDP_TRACE_FLAG_LABEL
,
597 "Label Mapping Sent to %s for %08x/%d\n",
599 us_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
600 us_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
);
602 us_attr
->state
= LDP_LSP_STATE_MAP_SENT
; /* SL.6,7 */
604 LDP_EXIT(g
->user_data
, "ldp_label_mapping_send");
605 return MPLS_SUCCESS
; /* SL.8 */
608 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_STATE
,
609 "No Label Resources\n");
611 while ((us_temp
= ldp_attr_find_upstream_state2(g
, s
, us_attr
->fec
,
612 LDP_LSP_STATE_REQ_RECV
)) != NULL
) { /* SL.9 */
613 ldp_notif_send(g
, s
, us_temp
, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE
);
615 s
->no_label_resource_sent
= MPLS_BOOL_TRUE
; /* SL.12 */
616 us_temp
->state
= LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT
; /* SL.13 */
619 LDP_EXIT(g
->user_data
, "ldp_label_mapping_send");
623 ldp_label_mapping_send_error
:
625 LDP_EXIT(g
->user_data
, "ldp_label_mapping_send-error");
629 void ldp_label_mapping_prepare_msg(ldp_mesg
* msg
, uint32_t msgid
,
632 mplsLdpLblMapMsg_t
*map
= NULL
;
637 ldp_mesg_prepare(msg
, MPLS_LBLMAP_MSGTYPE
, msgid
);
640 if (s_attr
->fecTlvExists
) {
641 /* JLEU: only 1 FEC is allowed!! */
642 map
->fecTlvExists
= 1;
643 map
->baseMsg
.msgLength
+= setupFecTlv(&map
->fecTlv
);
644 map
->baseMsg
.msgLength
+= addFecElem2FecTlv(&map
->fecTlv
,
645 &s_attr
->fecTlv
.fecElArray
[0]);
647 if (s_attr
->genLblTlvExists
) {
648 map
->genLblTlvExists
= 1;
649 map
->baseMsg
.msgLength
+= setupGenLblTlv(&map
->genLblTlv
,
650 s_attr
->genLblTlv
.label
);
652 if (s_attr
->atmLblTlvExists
) {
653 map
->atmLblTlvExists
= 1;
654 map
->baseMsg
.msgLength
+= setupAtmLblTlv(&map
->atmLblTlv
, 0, 0,
655 s_attr
->atmLblTlv
.flags
.flags
.vpi
, s_attr
->atmLblTlv
.vci
);
657 if (s_attr
->frLblTlvExists
) {
658 map
->frLblTlvExists
= 1;
659 map
->baseMsg
.msgLength
+= setupFrLblTlv(&map
->frLblTlv
, 0,
660 s_attr
->frLblTlv
.flags
.flags
.len
, s_attr
->frLblTlv
.flags
.flags
.dlci
);
662 if (s_attr
->hopCountTlvExists
) {
663 map
->hopCountTlvExists
= 1;
664 map
->baseMsg
.msgLength
+= setupHopCountTlv(&map
->hopCountTlv
,
665 s_attr
->hopCountTlv
.hcValue
);
667 if (s_attr
->pathVecTlvExists
) {
668 map
->pathVecTlvExists
= 1;
669 map
->baseMsg
.msgLength
+= setupPathTlv(&map
->pathVecTlv
);
670 for (i
= 0; i
< MPLS_MAXHOPSNUMBER
; i
++) {
671 if (s_attr
->pathVecTlv
.lsrId
[i
]) {
672 map
->baseMsg
.msgLength
+= addLsrId2PathTlv(&map
->pathVecTlv
,
673 s_attr
->pathVecTlv
.lsrId
[i
]);
678 if (s_attr
->lblMsgIdTlvExists
) {
680 if (s_attr
->lspidTlvExists
) {
682 if (s_attr
->trafficTlvExists
) {
687 mpls_return_enum
ldp_label_mapping_process(ldp_global
* g
, ldp_session
* s
,
688 ldp_adj
* a
, ldp_entity
* e
, ldp_attr
* r_attr
, ldp_fec
* f
)
690 mpls_return_enum retval
= MPLS_SUCCESS
;
691 ldp_session
*peer
= NULL
;
692 ldp_attr_list
*us_list
= NULL
;
693 ldp_attr_list
*ds_list
= NULL
;
694 ldp_attr
*ds_attr
= NULL
;
695 ldp_attr
*ds_temp
= NULL
;
696 ldp_attr
*us_attr
= NULL
;
697 ldp_attr
*us_temp
= NULL
;
699 ldp_nexthop
*nh
= NULL
;
701 ldp_outlabel
*out
= NULL
;
702 mpls_bool requested
= MPLS_BOOL_FALSE
;
703 ldp_attr
*existing
= NULL
;
704 mpls_bool need_request
= MPLS_BOOL_FALSE
;
706 LDP_ENTER(g
->user_data
, "ldp_label_mapping_process");
708 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
, LDP_TRACE_FLAG_LABEL
,
709 "Label Mapping Recv from %s for %08x/%d\n",
711 r_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
712 r_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
);
714 if ((ds_attr
= ldp_attr_find_downstream_state2(g
, s
, f
,
715 LDP_LSP_STATE_REQ_SENT
)) != NULL
) { /* LMp.1 */
716 /* just remove the req from the tree, we will use the r_attr sent to us */
717 ldp_attr_delete_downstream(g
, s
, ds_attr
);
718 requested
= MPLS_BOOL_TRUE
;
720 requested
= MPLS_BOOL_FALSE
;
724 ds_attr
->state
= LDP_LSP_STATE_MAP_RECV
; /* LMp.2 */
727 * ds_attr is the mapping we will keep and is NOT in the tree, unless
728 * it is an update mapping ...
730 if (Check_Received_Attributes(g
, s
, ds_attr
, MPLS_LBLMAP_MSGTYPE
) ==
731 MPLS_SUCCESS
) { /* LMp.3 */
736 * A loop was detected
738 if ((ds_list
= ldp_attr_find_downstream_all2(g
, s
, f
))) {
739 ds_temp
= MPLS_LIST_HEAD(ds_list
);
741 * check all the labels this session has received from "s" for "fec"
742 * do we have a duplicat?
745 if ((ds_temp
->state
== LDP_LSP_STATE_MAP_RECV
) && /* LMp.4 */
746 ldp_attr_is_equal(ds_temp
, ds_attr
, LDP_ATTR_LABEL
) == /* LMp.5 */
748 /* remove record of the label and remove it switching */
749 ldp_attr_remove_complete(g
, ds_temp
, MPLS_BOOL_TRUE
); /* LMp.6,7 */
751 * I think this is supposed to be 32 NOT 33, we need to release
756 ds_temp
= MPLS_LIST_NEXT(ds_list
, ds_temp
, _fs
);
760 LDP_PRINT(g
->user_data
, "Receive_Label_Map_8: send release");
761 if (ldp_label_release_send(g
, s
, ds_attr
, LDP_NOTIF_LOOP_DETECTED
) !=
762 MPLS_SUCCESS
) { /* LMp.8 */
763 retval
= MPLS_FAILURE
;
771 ds_temp
= ldp_attr_find_downstream_state2(g
, s
, f
, LDP_LSP_STATE_MAP_RECV
);
772 if (requested
== MPLS_BOOL_TRUE
||
773 g
->label_merge
== MPLS_BOOL_FALSE
|| !ds_temp
) {
774 /* !merging then this is always a new LSP
775 * merging w/o a recv'd mapping is a new LSP
776 * this check comes from Note 6
781 /* searching all recv'd attrs for matched mappings,
782 * stop after finding 1st match
784 if ((ds_list
= ldp_attr_find_downstream_all2(g
, s
, f
))) {
785 ds_temp
= MPLS_LIST_HEAD(ds_list
);
787 if (ds_temp
->state
== LDP_LSP_STATE_MAP_RECV
) { /* LMp.9 */
788 if (ldp_attr_is_equal(ds_attr
, ds_temp
, LDP_ATTR_LABEL
) ==
789 MPLS_BOOL_TRUE
) { /* LMp.10 */
791 * this mapping matches an existing mapping, but it
792 * could contain updated attributes
798 * we have been given another label for the same FEC and we
799 * didn't request it, release it
801 LDP_PRINT(g
->user_data
, "LMp.10 dup without req\n");
805 ds_temp
= MPLS_LIST_NEXT(ds_list
, ds_temp
, _fs
);
809 ldp_attr2ldp_attr(ds_attr
, existing
, LDP_ATTR_HOPCOUNT
| LDP_ATTR_PATH
|
810 LDP_ATTR_MSGID
| LDP_ATTR_LSPID
| LDP_ATTR_TRAFFIC
);
813 * no need to free ds_attr, since it was not added to the tree it
814 * will be deleted when we exit ldp_label_mapping_process(), see
815 * ldp_state_process().
819 * from this point on.... if this is an updated mapping then ds_attr
820 * is the existing mapping which has now been update, else ds_attr
826 * existing ONLY has a value for updated label mapping
828 nh
= ldp_nexthop_for_fec_session(f
,s
); /* LMp.11 */
831 * the following departs from the procedure, it allows for filtering
834 * Are we configured to accept and INSTALL this mapping?
836 if (mpls_policy_import_check(g
->user_data
, &f
->info
, &nh
->info
) ==
839 * policy has rejected it, store it away
841 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
, LDP_TRACE_FLAG_LABEL
,
842 "Label Mapping for %08x/%d from %s filtered by import policy\n",
843 r_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
844 r_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
, s
->session_name
);
847 ds_attr
->filtered
= MPLS_BOOL_TRUE
;
848 if (ds_attr
->outlabel
&& ds_attr
->outlabel
->switching
== MPLS_BOOL_TRUE
) {
849 /* the mapping has been filtered, but the original wasn't? */
853 ds_attr
->filtered
= MPLS_BOOL_TRUE
;
854 if (ldp_attr_insert_downstream(g
, s
, ds_attr
) != MPLS_SUCCESS
) {
855 retval
= MPLS_FAILURE
;
861 if (!nh
) { /* LMp.12 */
863 * if we did not find a nh hop for this FEC that corresponded to the
864 * MsgSource then the MsgSource is not a nexthop for the FEC
866 if (g
->label_retention_mode
== LDP_RETENTION_CONSERVATIVE
) { /* LMp.13C */
867 LDP_PRINT(g
->user_data
, "LMp.13C conservative\n");
874 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
, LDP_TRACE_FLAG_LABEL
,
875 "Session %s is not a valid nexthop for %08x/%d\n", s
->session_name
,
876 r_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
877 r_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
);
881 if (ldp_attr_insert_downstream(g
, s
, ds_attr
) != MPLS_SUCCESS
) {
882 retval
= MPLS_FAILURE
;
889 * this is slightly different form the procedure, we can still be
890 * transit for a FEC we are not configured to be ingress for.
891 * Either way we only need to do the "install for fwd/switching"
892 * only once. We could arrive here multiple times due to updates,
893 * only install it the first time
895 if ((!existing
) || (!existing
->outlabel
)) {
897 * we haven't installed it yet.
898 * Either new (!existing), or a result of a "Detect FEC Nexthop Change"
899 * and we had this mapping in our database (!existing->outlabel))
902 if (!(out
= ldp_outlabel_create_complete(g
, s
, ds_attr
, nh
))) {
903 LDP_PRINT(g
->user_data
, "LMp.15 failure creating outlabel\n");
907 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_ALL
, LDP_TRACE_FLAG_BINDING
,
908 "Out Label Added\n");
912 * are we configured to act as ingress for this FEC?
914 if (mpls_policy_ingress_check(g
->user_data
, &f
->info
, &nh
->info
) ==
915 MPLS_BOOL_TRUE
) { /* LMp.14 */
917 * yep, bind the label to the FEC
919 if (ds_attr
->ingress
!= MPLS_BOOL_TRUE
) {
922 ftn
.outsegment_index
= ds_attr
->outlabel
->info
.handle
;
923 memcpy(&ftn
.fec
, &f
->info
, sizeof(mpls_fec
));
924 lsr_cfg_ftn_set2(g
->lsr_handle
, &ftn
, LSR_CFG_ADD
|LSR_FTN_CFG_FEC
|
925 LSR_FTN_CFG_OUTSEGMENT
);
927 mpls_mpls_fec2out_add(g
->mpls_handle
, &f
->info
, &ds_attr
->outlabel
->info
);
929 ds_attr
->ingress
= MPLS_BOOL_TRUE
;
930 ds_attr
->outlabel
->merge_count
++;
931 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
, LDP_TRACE_FLAG_BINDING
,
932 "Acting as ingress for %08x/%d from %s\n",
933 r_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
934 r_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
, s
->session_name
);
938 /* create a set of attrs that we will fill and compare against
939 * if this mapping were to be propogate these are the attrs it would have
940 * by comparing what we did sent in the past to these, we con figure out
941 * if we need to send an updated mapping
943 memset(&dumb_attr
, 0, sizeof(ldp_attr
));
944 mpls_fec2fec_tlv(&f
->info
, &dumb_attr
.fecTlv
, 0);
945 dumb_attr
.fecTlvExists
= 1;
946 dumb_attr
.fecTlv
.numberFecElements
= 1;
949 * by definition (we received a label mapping that will be used) this
950 * LSR is _not_ the egress, so calculate a hop and path based on the
951 * mapping we received. We will compare this with mapping that have
952 * already been sent. If they differ, we will send an updated mapping
954 Prepare_Label_Mapping_Attributes(g
, s
, &f
->info
, ds_attr
, &dumb_attr
,
955 MPLS_BOOL_TRUE
, MPLS_BOOL_TRUE
, MPLS_BOOL_FALSE
);
959 * this is the first time we've seen this mapping, add it to the database.
960 * all future updates will modify this entry in place
963 if (ldp_attr_insert_downstream(g
, s
, ds_attr
) != MPLS_SUCCESS
) {
964 retval
= MPLS_FAILURE
;
969 peer
= MPLS_LIST_HEAD(&g
->session
);
970 while (peer
) { /* LMp.17 */
972 /* can't send messages to non-operational sessions */
973 if (peer
->state
!= LDP_STATE_OPERATIONAL
) {
978 * don't send the mapping to the session
979 * from which we recv'd the mapping
981 if (peer
->index
== s
->index
) {
986 * it is just as easy to walk the list of all upstream attr for this
987 * peer as it is to the individual check to see if we have sent a
988 * label mapping for this FEC LSP
992 if ((us_list
= ldp_attr_find_upstream_all2(g
, peer
, f
))) {
993 us_temp
= MPLS_LIST_HEAD(us_list
);
996 * if we have sent a label mapping for the FEC and that label mapping
997 * was an done in independent mode or it is part of an LSP created
998 * due as part of an existing received label mapping
1001 if (us_temp
->state
== LDP_LSP_STATE_MAP_SENT
) {
1003 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
,
1004 LDP_TRACE_FLAG_BINDING
, "Already sent mapping for %08x/%d to %s\n",
1005 r_attr
->fecTlv
.fecElArray
[0].addressEl
.address
,
1006 r_attr
->fecTlv
.fecElArray
[0].addressEl
.preLen
, peer
->session_name
);
1008 if ((!existing
) || (existing
->index
== us_temp
->ds_attr
->index
)) {
1010 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
,
1011 LDP_TRACE_FLAG_BINDING
, "Part of same LSP\n");
1014 if (ldp_attr_is_equal(us_temp
, &dumb_attr
,
1015 LDP_ATTR_HOPCOUNT
| LDP_ATTR_PATH
) != MPLS_BOOL_TRUE
) {
1017 LDP_TRACE_LOG(g
->user_data
, MPLS_TRACE_STATE_RECV
,
1018 LDP_TRACE_FLAG_BINDING
, "Propogating updated attrs\n");
1020 /* send an updated label mapping */
1021 if (ldp_label_mapping_with_xc(g
, us_temp
->session
, f
, &us_temp
,
1022 ds_attr
) != MPLS_SUCCESS
) { /* LMp.24-26 */
1023 retval
= MPLS_FAILURE
;
1029 us_temp
= MPLS_LIST_NEXT(us_list
, us_temp
, _fs
);
1033 if ((peer
->oper_distribution_mode
== LDP_DISTRIBUTION_UNSOLICITED
) &&
1034 (g
->lsp_control_mode
== LDP_CONTROL_ORDERED
)) { /* LMp.19 */
1037 * if we're not merging and we have multiple ORDERED DU sessions,
1038 * we will need to start requesting labels after we propogate the
1039 * mapping to the first peer
1041 if (need_request
== MPLS_BOOL_TRUE
) {
1042 if (ldp_attr_find_downstream_state2(g
, peer
, f
,
1043 LDP_LSP_STATE_REQ_SENT
) == NULL
) {
1045 * we don't have a request for FEC to peer outstanding, make one
1048 if (ldp_label_request_for_xc(g
, peer
, &f
->info
, NULL
, &ds_temp
) !=
1050 retval
= MPLS_FAILURE
;
1056 * We're in DU more, either we're merging, or we're not merging and
1057 * this is the first peer we're propogating this mapping to
1061 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_attr
, ds_attr
) !=
1063 retval
= MPLS_FAILURE
;
1067 * if we're not merging, we will need to request a label for
1070 if (g
->label_merge
== MPLS_BOOL_FALSE
) {
1071 need_request
= MPLS_BOOL_TRUE
;
1077 while ((us_temp
= ldp_attr_find_upstream_state2(g
, peer
, f
,
1078 LDP_LSP_STATE_REQ_RECV
))) {
1080 if (peer
->oper_distribution_mode
== LDP_DISTRIBUTION_UNSOLICITED
) {
1081 if (need_request
== MPLS_BOOL_TRUE
) {
1082 if (ldp_attr_find_downstream_state2(g
, peer
, f
,
1083 LDP_LSP_STATE_REQ_SENT
) == NULL
) {
1085 * we don't have a request for FEC to peer outstanding
1088 if (ldp_label_request_for_xc(g
, peer
, &f
->info
, us_temp
,
1089 &ds_temp
) != MPLS_SUCCESS
) {
1090 retval
= MPLS_FAILURE
;
1095 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_temp
,
1096 ds_attr
) != MPLS_SUCCESS
) {
1097 retval
= MPLS_FAILURE
;
1102 if ((us_list
= ldp_attr_find_upstream_all2(g
, peer
, f
))) {
1103 us_temp
= MPLS_LIST_HEAD(ds_list
);
1105 if (us_temp
->state
== LDP_LSP_STATE_REQ_RECV
) {
1106 if (need_request
== MPLS_BOOL_TRUE
) {
1107 if (ldp_attr_find_downstream_state2(g
, peer
, f
,
1108 LDP_LSP_STATE_REQ_SENT
) == NULL
) {
1110 * we don't have a request for FEC to peer outstanding
1113 if (ldp_label_request_for_xc(g
, peer
, &f
->info
, us_temp
,
1114 &ds_temp
) != MPLS_SUCCESS
) {
1115 retval
= MPLS_FAILURE
;
1120 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_temp
,
1121 ds_attr
) != MPLS_SUCCESS
) {
1122 retval
= MPLS_FAILURE
;
1126 * if we're not merging, we will need to request a label for
1129 if (g
->label_merge
== MPLS_BOOL_FALSE
) {
1130 need_request
= MPLS_BOOL_TRUE
;
1134 us_temp
= MPLS_LIST_NEXT(us_list
, us_temp
, _fs
);
1141 peer
= MPLS_LIST_NEXT(&g
->session
, peer
, _global
);
1145 LDP_EXIT(g
->user_data
, "ldp_label_mapping_process");
1149 LDP_PRINT(g
->user_data
, "Receive_Label_Map_32: send release");
1150 if (ldp_label_release_send(g
, s
, ds_attr
, LDP_NOTIF_NONE
) != MPLS_SUCCESS
) {
1151 retval
= MPLS_FAILURE
;
1153 LDP_EXIT(g
->user_data
, "ldp_label_mapping_process");