Re-work iff, addr, fec, nexthop life cycle.
[mpls-ldp-portable.git] / ldp / ldp_fec.c
blob3bfa039130e3d6f6c06391494e550030d0ae2dfc
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_fec.h"
12 #include "ldp_if.h"
13 #include "ldp_attr.h"
14 #include "ldp_addr.h"
15 #include "ldp_nexthop.h"
16 #include "ldp_session.h"
17 #include "ldp_inlabel.h"
18 #include "ldp_outlabel.h"
19 #include "ldp_global.h"
20 #include "ldp_label_mapping.h"
21 #include "ldp_label_request.h"
22 #include "ldp_label_abort.h"
23 #include "ldp_label_rel_with.h"
24 #include "mpls_assert.h"
25 #include "mpls_compare.h"
26 #include "mpls_mm_impl.h"
27 #include "mpls_tree_impl.h"
28 #include "mpls_policy_impl.h"
29 #include "mpls_trace_impl.h"
31 #if MPLS_USE_LSR
32 #include "lsr_cfg.h"
33 #else
34 #include "mpls_mpls_impl.h"
35 #endif
37 static uint32_t _ldp_fec_next_index = 1;
39 static mpls_return_enum ldp_fec_insert(ldp_global *g, ldp_fec * fec)
41 mpls_return_enum retval = MPLS_SUCCESS;
42 uint32_t key;
43 uint8_t len;
45 MPLS_ASSERT(g && fec);
46 LDP_ENTER(g->user_data, "ldp_fec_insert");
48 switch(fec->info.type) {
49 case MPLS_FEC_PREFIX:
50 key = fec->info.u.prefix.network.u.ipv4;
51 len = fec->info.u.prefix.length;
52 break;
53 case MPLS_FEC_HOST:
54 key = fec->info.u.host.u.ipv4;
55 len = 32;
56 break;
57 case MPLS_FEC_L2CC:
58 /* they had better insert it into the global list */
59 LDP_EXIT(g->user_data, "ldp_fec_insert: l2cc");
60 return MPLS_SUCCESS;
61 default:
62 MPLS_ASSERT(0);
65 if (mpls_tree_insert(g->fec_tree, key, len, (void *)fec) != MPLS_SUCCESS) {
66 LDP_PRINT(g->user_data, "ldp_fec_insert: error adding fec\n");
67 retval = MPLS_FATAL;
70 LDP_EXIT(g->user_data, "ldp_fec_insert");
71 return retval;
74 static void ldp_fec_remove(ldp_global *g, mpls_fec *fec)
76 ldp_fec *f = NULL;
77 uint32_t key;
78 uint8_t len;
80 MPLS_ASSERT(g && fec);
81 LDP_ENTER(g->user_data, "ldp_fec_remove");
83 switch(fec->type) {
84 case MPLS_FEC_PREFIX:
85 key = fec->u.prefix.network.u.ipv4;
86 len = fec->u.prefix.length;
87 break;
88 case MPLS_FEC_HOST:
89 key = fec->u.host.u.ipv4;
90 len = 32;
91 break;
92 case MPLS_FEC_L2CC:
93 /* they had better remove it from the global list */
94 LDP_EXIT(g->user_data, "ldp_fec_remove");
95 return;
96 default:
97 MPLS_ASSERT(0);
100 mpls_tree_remove(g->fec_tree, key, len, (void **)&f);
102 MPLS_ASSERT(f);
104 LDP_EXIT(g->user_data, "ldp_fec_remove");
107 static uint32_t _ldp_fec_get_next_index()
109 uint32_t retval = _ldp_fec_next_index;
111 _ldp_fec_next_index++;
112 if (retval > _ldp_fec_next_index) {
113 _ldp_fec_next_index = 1;
115 return retval;
118 ldp_fec *ldp_fec_create(ldp_global *g, mpls_fec *f)
120 ldp_fec *fec = (ldp_fec *) mpls_malloc(sizeof(ldp_fec));
122 if (fec != NULL) {
123 memset(fec, 0, sizeof(ldp_fec));
125 * note: this is init to 1 for a reason!
126 * We're placing it in the global list, so this is our refcnt
127 * when this refcnt gets to zero, it will be removed from the
128 * global list and deleted
131 * TESTING: jleu 6/7/2004, since I want the FEC to be cleaned up
132 * when it no longer has a nexthop, addr, or label, the only things that
133 * should increment the ref are those (nh, addr, label etc), not global
134 * nor inserting into the tree. I also added this comment in
135 * _ldp_global_add_fec()
136 MPLS_REFCNT_INIT(fec, 1);
138 MPLS_LIST_ELEM_INIT(fec, _global);
139 MPLS_LIST_ELEM_INIT(fec, _inlabel);
140 MPLS_LIST_ELEM_INIT(fec, _outlabel);
141 MPLS_LIST_ELEM_INIT(fec, _fec);
142 MPLS_LIST_INIT(&fec->nh_root, ldp_nexthop);
143 MPLS_LIST_INIT(&fec->fs_root_us, ldp_fs);
144 MPLS_LIST_INIT(&fec->fs_root_ds, ldp_fs);
145 fec->index = _ldp_fec_get_next_index();
146 mpls_fec2ldp_fec(f,fec);
148 _ldp_global_add_fec(g, fec);
149 ldp_fec_insert(g, fec);
151 return fec;
154 void ldp_fec_delete(ldp_global *g, ldp_fec * fec)
156 fprintf(stderr, "fec delete: %08x/%d\n", fec->info.u.prefix.network.u.ipv4,
157 fec->info.u.prefix.length);
158 ldp_fec_remove(g, &fec->info);
159 _ldp_global_del_fec(g, fec);
160 mpls_free(fec);
163 ldp_fec *ldp_fec_find(ldp_global *g, mpls_fec *fec)
165 ldp_fec *f = NULL;
166 uint32_t key;
167 uint8_t len;
169 switch(fec->type) {
170 case MPLS_FEC_PREFIX:
171 key = fec->u.prefix.network.u.ipv4;
172 len = fec->u.prefix.length;
173 break;
174 case MPLS_FEC_HOST:
175 key = fec->u.host.u.ipv4;
176 len = 32;
177 break;
178 case MPLS_FEC_L2CC:
179 if (ldp_global_find_fec(g, fec, &f) == MPLS_SUCCESS) {
180 return f;
182 return NULL;
183 default:
184 MPLS_ASSERT(0);
187 if (mpls_tree_get(g->fec_tree, key, len, (void **)&f) != MPLS_SUCCESS) {
188 return NULL;
190 return f;
193 ldp_fec *ldp_fec_find2(ldp_global *g, mpls_fec *fec)
195 ldp_fec *f = NULL;
196 f = ldp_fec_find(g, fec);
197 if (!f) {
198 f = ldp_fec_create(g, fec);
200 return f;
203 ldp_nexthop *ldp_fec_nexthop_find(ldp_fec *f, mpls_nexthop *n)
205 ldp_nexthop *nh = NULL;
207 MPLS_ASSERT(f && n);
209 nh = MPLS_LIST_HEAD(&f->nh_root);
210 while (nh) {
211 if (!mpls_nexthop_compare(&nh->info, n)) {
212 return nh;
214 nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec);
217 return NULL;
220 mpls_return_enum ldp_fec_find_nexthop_index(ldp_fec *f, int index,
221 ldp_nexthop **n)
223 ldp_nexthop *nh = NULL;
225 MPLS_ASSERT(f);
227 if (index > 0) {
229 /* because we sort our inserts by index, this lets us know
230 if we've "walked" past the end of the list */
232 nh = MPLS_LIST_TAIL(&f->nh_root);
233 if (!nh || nh->index < index) {
234 *n = NULL;
235 return MPLS_END_OF_LIST;
238 nh = MPLS_LIST_HEAD(&f->nh_root);
239 do {
240 if (nh->index == index) {
241 *n = nh;
242 return MPLS_SUCCESS;
244 } while((nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec)));
246 *n = NULL;
247 return MPLS_FAILURE;
250 mpls_return_enum ldp_fec_add_nexthop(ldp_global *g, ldp_fec * f,
251 ldp_nexthop * nh)
253 MPLS_ASSERT(f && nh);
255 MPLS_REFCNT_HOLD(nh);
256 MPLS_LIST_ADD_HEAD(&f->nh_root, nh, _fec, ldp_nexthop);
258 ldp_nexthop_add_fec(nh, f);
260 if (nh->info.type & MPLS_NH_IP) {
261 ldp_addr *addr = NULL;
262 if (!(addr = ldp_addr_find(g, &nh->info.ip))) {
263 if (!(addr = ldp_addr_insert(g, &nh->info.ip))) {
264 goto ldp_fec_add_nexthop_error;
268 ldp_addr_add_nexthop(addr, nh);
271 if (nh->info.type & MPLS_NH_IF) {
272 ldp_if *iff = NULL;
273 if ((iff = ldp_global_find_if_handle(g, nh->info.if_handle))) {
274 ldp_if_add_nexthop(iff, nh);
278 if (nh->info.type & MPLS_NH_OUTSEGMENT) {
279 ldp_outlabel *out = NULL;
280 MPLS_ASSERT((out = ldp_global_find_outlabel_handle(g,
281 nh->info.outsegment_handle)));
283 ldp_outlabel_add_nexthop(out, nh);
285 return MPLS_SUCCESS;
287 ldp_fec_add_nexthop_error:
289 ldp_fec_del_nexthop(g, f, nh);
290 return MPLS_FATAL;
293 void ldp_fec_del_nexthop(ldp_global *g, ldp_fec * f, ldp_nexthop *nh)
295 MPLS_ASSERT(f && nh);
297 if (nh->addr) {
298 ldp_addr_del_nexthop(g, nh->addr, nh);
300 if (nh->iff) {
301 ldp_if_del_nexthop(g, nh->iff, nh);
303 if (nh->outlabel) {
304 ldp_outlabel_del_nexthop(g, nh->outlabel, nh);
307 MPLS_LIST_REMOVE(&f->nh_root, nh, _fec);
308 ldp_nexthop_del_fec(g, nh);
310 MPLS_REFCNT_RELEASE2(g, nh, ldp_nexthop_delete);
313 mpls_return_enum ldp_fec_process_add(ldp_global * g, ldp_fec * f,
314 ldp_nexthop *nh, ldp_session *nh_session)
316 ldp_session *peer = NULL;
317 ldp_attr *ds_attr = NULL;
318 ldp_attr *us_attr = NULL;
319 mpls_bool egress = MPLS_BOOL_FALSE;
320 ldp_outlabel *out;
322 LDP_ENTER(g->user_data, "ldp_fec_process_add");
325 * find the info about the next hop for this FEC
327 if (!nh_session) {
328 nh_session = ldp_session_for_nexthop(nh);
331 if (nh_session) {
332 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
333 LDP_LSP_STATE_MAP_RECV);
334 if (ds_attr && !ds_attr->outlabel) {
335 out = ldp_outlabel_create_complete(g, nh_session, ds_attr, nh);
336 if (!out) {
337 return MPLS_FAILURE;
339 ds_attr->outlabel = out;
344 * for every peer except the nh hop peer, check to see if we need to
345 * send a mapping
347 peer = MPLS_LIST_HEAD(&g->session);
348 while (peer != NULL) { /* FEC.1 */
349 if ((peer->state != LDP_STATE_OPERATIONAL) ||
350 (nh_session && peer->index == nh_session->index)) {
351 goto next_peer;
353 /* have I already sent a mapping for FEC to peer */
354 if ((us_attr = ldp_attr_find_upstream_state2(g, peer, f,
355 LDP_LSP_STATE_MAP_SENT))) {
356 /* yep, don't send another */
357 if (ds_attr) {
358 if (ldp_inlabel_add_outlabel(g, us_attr->inlabel,
359 ds_attr->outlabel) != MPLS_SUCCESS) {
360 return MPLS_FAILURE;
363 goto next_peer;
366 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
367 if (g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) {
368 us_attr =
369 ldp_attr_find_upstream_state2(g, peer, f, LDP_LSP_STATE_REQ_RECV);
371 /* FEC.1.DUI3,4 */
372 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
373 MPLS_SUCCESS) {
374 if (!us_attr->in_tree) {
375 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
377 goto next_peer;
379 } else {
381 *LDP_CONTROL_ORDERED
384 if (ds_attr || egress == MPLS_BOOL_TRUE) { /* FEC.1.DUO2 */
385 if (!(us_attr = ldp_attr_create(&f->info))) {
386 return MPLS_FAILURE;
388 /* FEC.1.DUO3-4 */
389 if ((egress == MPLS_BOOL_TRUE) && (mpls_policy_egress_check(
390 g->user_data, &f->info, &nh->info) == MPLS_BOOL_TRUE)) {
391 goto next_peer;
394 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
395 MPLS_SUCCESS) {
396 return MPLS_FAILURE;
401 next_peer:
402 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
405 if (ds_attr) { /* FEC.2 */
406 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) ==
407 MPLS_FAILURE) { /* FEC.5 */
408 return MPLS_FAILURE;
410 return MPLS_SUCCESS;
414 * LDP_DISTRIBUTION_ONDEMAND
416 /* FEC.3 */
417 if (nh_session &&
418 nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND) {
419 /* assume we're always "request when needed" */
420 ds_attr = NULL;
421 if (ldp_label_request_for_xc(g, nh_session, &f->info, NULL, &ds_attr) ==
422 MPLS_FAILURE) { /* FEC.4 */
423 return MPLS_FAILURE;
427 LDP_EXIT(g->user_data, "ldp_fec_process_add");
429 return MPLS_SUCCESS; /* FEC.6 */
432 mpls_return_enum ldp_fec_process_change(ldp_global * g, ldp_fec * f,
433 ldp_nexthop *nh, ldp_nexthop *nh_old, ldp_session *nh_session_old) {
434 ldp_session *peer = NULL;
435 ldp_attr *us_attr = NULL;
436 ldp_attr *ds_attr = NULL;
437 ldp_session *nh_session = NULL;
439 LDP_ENTER(g->user_data, "ldp_fec_process_change");
441 if (!nh_session_old) {
442 nh_session_old = ldp_session_for_nexthop(nh_old);
446 * NH 1-5 decide if we need to release an existing mapping
448 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f,
449 LDP_LSP_STATE_MAP_RECV);
450 if (!ds_attr) { /* NH.1 */
451 goto Detect_Change_Fec_Next_Hop_6;
454 if (ds_attr->ingress == MPLS_BOOL_TRUE) {
456 #if MPLS_USE_LSR
457 lsr_ftn ftn;
458 ftn.outsegment_index = ds_attr->outlabel->info.handle;
459 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
460 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_DEL);
461 #else
462 mpls_mpls_fec2out_del(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
463 #endif
464 ds_attr->ingress = MPLS_BOOL_FALSE;
465 ds_attr->outlabel->merge_count--;
468 if (g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */
469 ldp_attr *us_temp;
470 us_attr = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
471 while (us_attr) {
472 /* need to walk the list in such a way as not to
473 * "pull the rug out from under me self"
475 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_attr, _ds_attr);
476 if (us_attr->state == LDP_LSP_STATE_MAP_SENT) {
477 ldp_inlabel_del_outlabel(g, us_attr->inlabel); /* NH.2 */
478 ldp_attr_del_us2ds(us_attr, ds_attr);
480 us_attr = us_temp;
482 goto Detect_Change_Fec_Next_Hop_6;
485 ldp_label_release_send(g, nh_session_old, ds_attr, LDP_NOTIF_NONE); /* NH.4 */
486 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* NH.2,5 */
488 Detect_Change_Fec_Next_Hop_6:
491 * NH 6-9 decides is we need to send a label request abort
493 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f,
494 LDP_LSP_STATE_REQ_SENT);
495 if (ds_attr) { /* NH.6 */
496 if (g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */
497 /* NH.8,9 */
498 if (ldp_label_abort_send(g, nh_session_old, ds_attr) != MPLS_SUCCESS) {
499 return MPLS_FAILURE;
505 * NH 10-12 decides if we can use a mapping from our database
507 if (!(nh_session = ldp_get_next_hop_session_for_fec2(f,nh))) {
508 goto Detect_Change_Fec_Next_Hop_16;
511 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
512 LDP_LSP_STATE_MAP_RECV);
513 if (!ds_attr) { /* NH.11 */
514 goto Detect_Change_Fec_Next_Hop_13;
517 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) !=
518 MPLS_SUCCESS) { /* NH.12 */
519 return MPLS_FAILURE;
521 goto Detect_Change_Fec_Next_Hop_20;
523 Detect_Change_Fec_Next_Hop_13:
526 * NH 13-15 decides if we need to make a label request
528 if (nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND &&
529 g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) {
530 /* NH.14-15 */
531 if (ldp_label_request_for_xc(g, nh_session, &f->info, NULL, &ds_attr) !=
532 MPLS_SUCCESS) {
533 return MPLS_FAILURE;
536 goto Detect_Change_Fec_Next_Hop_20;
538 Detect_Change_Fec_Next_Hop_16:
540 peer = MPLS_LIST_HEAD(&g->session);
541 while (peer) {
542 if (peer->state == LDP_STATE_OPERATIONAL) {
543 us_attr = ldp_attr_find_upstream_state2(g, peer, f,
544 LDP_LSP_STATE_MAP_SENT);
545 if (us_attr) { /* NH.17 */
546 if (ldp_label_withdraw_send(g, peer, us_attr, LDP_NOTIF_NONE) !=
547 MPLS_SUCCESS) { /* NH.18 */
548 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
549 return MPLS_FAILURE;
553 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
556 Detect_Change_Fec_Next_Hop_20:
558 LDP_EXIT(g->user_data, "ldp_fec_process_change");
560 return MPLS_SUCCESS;
563 void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b)
565 memcpy(&b->info, a, sizeof(mpls_fec));
568 void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int i)
570 tlv->fecElArray[i].addressEl.addressFam = 1;
572 switch (lf->type) {
573 case MPLS_FEC_PREFIX:
574 tlv->fecElArray[i].addressEl.type = MPLS_PREFIX_FEC;
575 tlv->fecElArray[i].addressEl.preLen = lf->u.prefix.length;
576 tlv->fecElArray[i].addressEl.address = lf->u.prefix.network.u.ipv4;
577 tlv->fecElemTypes[i] = MPLS_PREFIX_FEC;
578 break;
579 case MPLS_FEC_HOST:
580 tlv->fecElArray[i].addressEl.type = MPLS_HOSTADR_FEC;
581 tlv->fecElArray[i].addressEl.preLen = MPLS_IPv4LEN;
582 tlv->fecElArray[i].addressEl.address = lf->u.host.u.ipv4;
583 tlv->fecElemTypes[i] = MPLS_HOSTADR_FEC;
584 break;
585 default:
586 MPLS_ASSERT(0);
590 void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int i, mpls_fec * lf) {
591 switch (tlv->fecElemTypes[i]) {
592 case MPLS_PREFIX_FEC:
593 lf->type = MPLS_FEC_PREFIX;
594 lf->u.prefix.length = tlv->fecElArray[i].addressEl.preLen;
595 lf->u.prefix.network.u.ipv4 = tlv->fecElArray[i].addressEl.address;
596 lf->u.prefix.network.type = MPLS_FAMILY_IPV4;
597 break;
598 case MPLS_HOSTADR_FEC:
599 lf->type = MPLS_FEC_HOST;
600 lf->u.host.u.ipv4 = tlv->fecElArray[i].addressEl.address;
601 lf->u.host.type = MPLS_FAMILY_IPV4;
602 break;
603 default:
604 MPLS_ASSERT(0);
608 mpls_bool ldp_fec_empty(ldp_fec *fec)
610 if (MPLS_LIST_EMPTY(&fec->fs_root_us) &&
611 MPLS_LIST_EMPTY(&fec->nh_root) &&
612 MPLS_LIST_EMPTY(&fec->fs_root_ds)) {
613 return MPLS_BOOL_TRUE;
615 return MPLS_BOOL_FALSE;