LDP now reacts to FEC adds and deletes
[mpls-ldp-portable.git] / ldp / ldp_fec.c
blob5a730893b87f7f24b9553ac87406d5e85cd1d8ef
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
130 MPLS_REFCNT_INIT(fec, 1);
131 MPLS_LIST_ELEM_INIT(fec, _global);
132 MPLS_LIST_ELEM_INIT(fec, _inlabel);
133 MPLS_LIST_ELEM_INIT(fec, _outlabel);
134 MPLS_LIST_ELEM_INIT(fec, _fec);
135 MPLS_LIST_INIT(&fec->nh_root, ldp_nexthop);
136 MPLS_LIST_INIT(&fec->fs_root_us, ldp_fs);
137 MPLS_LIST_INIT(&fec->fs_root_ds, ldp_fs);
138 fec->index = _ldp_fec_get_next_index();
139 mpls_fec2ldp_fec(f,fec);
141 _ldp_global_add_fec(g, fec);
142 ldp_fec_insert(g, fec);
144 return fec;
147 void ldp_fec_delete(ldp_global *g, ldp_fec * fec)
149 fprintf(stderr, "fec delete: %08x/%d\n", fec->info.u.prefix.network.u.ipv4,
150 fec->info.u.prefix.length);
151 ldp_fec_remove(g, &fec->info);
152 _ldp_global_del_fec(g, fec);
153 mpls_free(fec);
156 ldp_fec *ldp_fec_find(ldp_global *g, mpls_fec *fec)
158 ldp_fec *f = NULL;
159 uint32_t key;
160 uint8_t len;
162 switch(fec->type) {
163 case MPLS_FEC_PREFIX:
164 key = fec->u.prefix.network.u.ipv4;
165 len = fec->u.prefix.length;
166 break;
167 case MPLS_FEC_HOST:
168 key = fec->u.host.u.ipv4;
169 len = 32;
170 break;
171 case MPLS_FEC_L2CC:
172 if (ldp_global_find_fec(g, fec, &f) == MPLS_SUCCESS) {
173 return f;
175 return NULL;
176 default:
177 MPLS_ASSERT(0);
180 if (mpls_tree_get(g->fec_tree, key, len, (void **)&f) != MPLS_SUCCESS) {
181 return NULL;
183 return f;
186 ldp_fec *ldp_fec_find2(ldp_global *g, mpls_fec *fec)
188 ldp_fec *f = NULL;
189 f = ldp_fec_find(g, fec);
190 if (!f) {
191 f = ldp_fec_create(g, fec);
193 return f;
196 ldp_nexthop *ldp_fec_nexthop_find(ldp_fec *f, mpls_nexthop *n)
198 ldp_nexthop *nh = NULL;
200 MPLS_ASSERT(f && n);
202 nh = MPLS_LIST_HEAD(&f->nh_root);
203 while (nh) {
204 if (!mpls_nexthop_compare(&nh->info, n)) {
205 return nh;
207 nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec);
210 return NULL;
213 mpls_return_enum ldp_fec_find_nexthop_index(ldp_fec *f, int index,
214 ldp_nexthop **n)
216 ldp_nexthop *nh = NULL;
218 MPLS_ASSERT(f);
220 if (index > 0) {
222 /* because we sort our inserts by index, this lets us know
223 if we've "walked" past the end of the list */
225 nh = MPLS_LIST_TAIL(&f->nh_root);
226 if (!nh || nh->index < index) {
227 *n = NULL;
228 return MPLS_END_OF_LIST;
231 nh = MPLS_LIST_HEAD(&f->nh_root);
232 do {
233 if (nh->index == index) {
234 *n = nh;
235 return MPLS_SUCCESS;
237 } while((nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec)));
239 *n = NULL;
240 return MPLS_FAILURE;
243 mpls_return_enum ldp_fec_add_nexthop(ldp_global *g, ldp_fec * f,
244 ldp_nexthop * nh)
246 MPLS_ASSERT(f && nh);
248 MPLS_REFCNT_HOLD(nh);
249 MPLS_LIST_ADD_HEAD(&f->nh_root, nh, _fec, ldp_nexthop);
251 ldp_nexthop_add_fec(nh, f);
253 if (nh->info.type & MPLS_NH_IP) {
254 ldp_addr *addr = NULL;
255 if (!(addr = ldp_addr_find(g, &nh->info.ip))) {
256 if (!(addr = ldp_addr_insert(g, &nh->info.ip))) {
257 goto ldp_fec_add_nexthop_error;
261 ldp_addr_add_nexthop(addr, nh);
264 if (nh->info.type & MPLS_NH_IF) {
265 ldp_if *iff = NULL;
266 if ((iff = ldp_global_find_if_handle(g, nh->info.if_handle))) {
267 ldp_if_add_nexthop(iff, nh);
271 if (nh->info.type & MPLS_NH_OUTSEGMENT) {
272 ldp_outlabel *out = NULL;
273 MPLS_ASSERT((out = ldp_global_find_outlabel_handle(g,
274 nh->info.outsegment_handle)));
276 ldp_outlabel_add_nexthop(out, nh);
278 return MPLS_SUCCESS;
280 ldp_fec_add_nexthop_error:
282 ldp_fec_del_nexthop(g, f, nh);
283 return MPLS_FATAL;
286 void ldp_fec_del_nexthop(ldp_global *g, ldp_fec * f, ldp_nexthop *nh)
288 MPLS_ASSERT(f && nh);
290 if (nh->addr) {
291 ldp_addr_del_nexthop(g, nh->addr, nh);
293 if (nh->iff) {
294 ldp_if_del_nexthop(g, nh->iff, nh);
296 if (nh->outlabel) {
297 ldp_outlabel_del_nexthop(nh->outlabel, nh);
300 MPLS_LIST_REMOVE(&f->nh_root, nh, _fec);
301 ldp_nexthop_del_fec(nh);
303 MPLS_REFCNT_RELEASE(nh, ldp_nexthop_delete);
306 mpls_return_enum ldp_fec_process_add(ldp_global * g, ldp_fec * f,
307 ldp_nexthop *nh, ldp_session *nh_session)
309 ldp_session *peer = NULL;
310 ldp_attr *ds_attr = NULL;
311 ldp_attr *us_attr = NULL;
312 mpls_bool egress = MPLS_BOOL_FALSE;
313 ldp_outlabel *out;
315 LDP_ENTER(g->user_data, "ldp_fec_process_add");
318 * find the info about the next hop for this FEC
320 if (!nh_session) {
321 nh_session = ldp_session_for_nexthop(nh);
324 if (nh_session) {
325 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
326 LDP_LSP_STATE_MAP_RECV);
327 if (ds_attr && !ds_attr->outlabel) {
328 out = ldp_outlabel_create_complete(g, nh_session, ds_attr, nh);
329 if (!out) {
330 return MPLS_FAILURE;
332 ds_attr->outlabel = out;
337 * for every peer except the nh hop peer, check to see if we need to
338 * send a mapping
340 peer = MPLS_LIST_HEAD(&g->session);
341 while (peer != NULL) { /* FEC.1 */
342 if ((peer->state != LDP_STATE_OPERATIONAL) ||
343 (nh_session && peer->index == nh_session->index)) {
344 goto next_peer;
346 /* have I already sent a mapping for FEC to peer */
347 if ((us_attr = ldp_attr_find_upstream_state2(g, peer, f,
348 LDP_LSP_STATE_MAP_SENT))) {
349 /* yep, don't send another */
350 if (ds_attr) {
351 if (ldp_inlabel_add_outlabel(g, us_attr->inlabel,
352 ds_attr->outlabel) != MPLS_SUCCESS) {
353 return MPLS_FAILURE;
356 goto next_peer;
359 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
360 if (g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) {
361 us_attr =
362 ldp_attr_find_upstream_state2(g, peer, f, LDP_LSP_STATE_REQ_RECV);
364 /* FEC.1.DUI3,4 */
365 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
366 MPLS_SUCCESS) {
367 if (!us_attr->in_tree) {
368 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
370 goto next_peer;
372 } else {
374 *LDP_CONTROL_ORDERED
377 if (ds_attr || egress == MPLS_BOOL_TRUE) { /* FEC.1.DUO2 */
378 if (!(us_attr = ldp_attr_create(&f->info))) {
379 return MPLS_FAILURE;
381 /* FEC.1.DUO3-4 */
382 if ((egress == MPLS_BOOL_TRUE) && (mpls_policy_egress_check(
383 g->user_data, &f->info, &nh->info) == MPLS_BOOL_TRUE)) {
384 goto next_peer;
387 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
388 MPLS_SUCCESS) {
389 return MPLS_FAILURE;
394 next_peer:
395 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
398 if (ds_attr) { /* FEC.2 */
399 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) ==
400 MPLS_FAILURE) { /* FEC.5 */
401 return MPLS_FAILURE;
403 return MPLS_SUCCESS;
407 * LDP_DISTRIBUTION_ONDEMAND
409 /* FEC.3 */
410 if (nh_session &&
411 nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND) {
412 /* assume we're always "request when needed" */
413 ds_attr = NULL;
414 if (ldp_label_request_for_xc(g, nh_session, &f->info, NULL, &ds_attr) ==
415 MPLS_FAILURE) { /* FEC.4 */
416 return MPLS_FAILURE;
420 LDP_EXIT(g->user_data, "ldp_fec_process_add");
422 return MPLS_SUCCESS; /* FEC.6 */
425 mpls_return_enum ldp_fec_process_change(ldp_global * g, ldp_fec * f,
426 ldp_nexthop *nh, ldp_nexthop *nh_old, ldp_session *nh_session_old) {
427 ldp_session *peer = NULL;
428 ldp_attr *us_attr = NULL;
429 ldp_attr *ds_attr = NULL;
430 ldp_session *nh_session = NULL;
432 LDP_ENTER(g->user_data, "ldp_fec_process_change");
434 if (!nh_session_old) {
435 nh_session_old = ldp_session_for_nexthop(nh_old);
439 * NH 1-5 decide if we need to release an existing mapping
441 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f,
442 LDP_LSP_STATE_MAP_RECV);
443 if (!ds_attr) { /* NH.1 */
444 goto Detect_Change_Fec_Next_Hop_6;
447 if (ds_attr->ingress == MPLS_BOOL_TRUE) {
449 #if MPLS_USE_LSR
450 lsr_ftn ftn;
451 ftn.outsegment_index = ds_attr->outlabel->info.handle;
452 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
453 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_DEL);
454 #else
455 mpls_mpls_fec2out_del(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
456 #endif
457 ds_attr->ingress = MPLS_BOOL_FALSE;
458 ds_attr->outlabel->merge_count--;
461 if (g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */
462 ldp_attr *us_temp;
463 us_attr = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
464 while (us_attr) {
465 /* need to walk the list in such a way as not to
466 * "pull the rug out from under me self"
468 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_attr, _ds_attr);
469 if (us_attr->state == LDP_LSP_STATE_MAP_SENT) {
470 ldp_inlabel_del_outlabel(g, us_attr->inlabel); /* NH.2 */
471 ldp_attr_del_us2ds(us_attr, ds_attr);
473 us_attr = us_temp;
475 goto Detect_Change_Fec_Next_Hop_6;
478 ldp_label_release_send(g, nh_session_old, ds_attr, LDP_NOTIF_NONE); /* NH.4 */
479 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* NH.2,5 */
481 Detect_Change_Fec_Next_Hop_6:
484 * NH 6-9 decides is we need to send a label request abort
486 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f,
487 LDP_LSP_STATE_REQ_SENT);
488 if (ds_attr) { /* NH.6 */
489 if (g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */
490 /* NH.8,9 */
491 if (ldp_label_abort_send(g, nh_session_old, ds_attr) != MPLS_SUCCESS) {
492 return MPLS_FAILURE;
498 * NH 10-12 decides if we can use a mapping from our database
500 if (!(nh_session = ldp_get_next_hop_session_for_fec2(f,nh))) {
501 goto Detect_Change_Fec_Next_Hop_16;
504 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
505 LDP_LSP_STATE_MAP_RECV);
506 if (!ds_attr) { /* NH.11 */
507 goto Detect_Change_Fec_Next_Hop_13;
510 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) !=
511 MPLS_SUCCESS) { /* NH.12 */
512 return MPLS_FAILURE;
514 goto Detect_Change_Fec_Next_Hop_20;
516 Detect_Change_Fec_Next_Hop_13:
519 * NH 13-15 decides if we need to make a label request
521 if (nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND &&
522 g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) {
523 /* NH.14-15 */
524 if (ldp_label_request_for_xc(g, nh_session, &f->info, NULL, &ds_attr) !=
525 MPLS_SUCCESS) {
526 return MPLS_FAILURE;
529 goto Detect_Change_Fec_Next_Hop_20;
531 Detect_Change_Fec_Next_Hop_16:
533 peer = MPLS_LIST_HEAD(&g->session);
534 while (peer) {
535 if (peer->state == LDP_STATE_OPERATIONAL) {
536 us_attr = ldp_attr_find_upstream_state2(g, peer, f,
537 LDP_LSP_STATE_MAP_SENT);
538 if (us_attr) { /* NH.17 */
539 if (ldp_label_withdraw_send(g, peer, us_attr, LDP_NOTIF_NONE) !=
540 MPLS_SUCCESS) { /* NH.18 */
541 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
542 return MPLS_FAILURE;
546 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
549 Detect_Change_Fec_Next_Hop_20:
551 LDP_EXIT(g->user_data, "ldp_fec_process_change");
553 return MPLS_SUCCESS;
556 void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b)
558 memcpy(&b->info, a, sizeof(mpls_fec));
561 void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int i)
563 tlv->fecElArray[i].addressEl.addressFam = 1;
565 switch (lf->type) {
566 case MPLS_FEC_PREFIX:
567 tlv->fecElArray[i].addressEl.type = MPLS_PREFIX_FEC;
568 tlv->fecElArray[i].addressEl.preLen = lf->u.prefix.length;
569 tlv->fecElArray[i].addressEl.address = lf->u.prefix.network.u.ipv4;
570 tlv->fecElemTypes[i] = MPLS_PREFIX_FEC;
571 break;
572 case MPLS_FEC_HOST:
573 tlv->fecElArray[i].addressEl.type = MPLS_HOSTADR_FEC;
574 tlv->fecElArray[i].addressEl.preLen = MPLS_IPv4LEN;
575 tlv->fecElArray[i].addressEl.address = lf->u.host.u.ipv4;
576 tlv->fecElemTypes[i] = MPLS_HOSTADR_FEC;
577 break;
578 default:
579 MPLS_ASSERT(0);
583 void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int i, mpls_fec * lf) {
584 switch (tlv->fecElemTypes[i]) {
585 case MPLS_PREFIX_FEC:
586 lf->type = MPLS_FEC_PREFIX;
587 lf->u.prefix.length = tlv->fecElArray[i].addressEl.preLen;
588 lf->u.prefix.network.u.ipv4 = tlv->fecElArray[i].addressEl.address;
589 lf->u.prefix.network.type = MPLS_FAMILY_IPV4;
590 break;
591 case MPLS_HOSTADR_FEC:
592 lf->type = MPLS_FEC_HOST;
593 lf->u.host.u.ipv4 = tlv->fecElArray[i].addressEl.address;
594 lf->u.host.type = MPLS_FAMILY_IPV4;
595 break;
596 default:
597 MPLS_ASSERT(0);
601 mpls_bool ldp_fec_empty(ldp_fec *fec)
603 if (MPLS_LIST_EMPTY(&fec->fs_root_us) &&
604 MPLS_LIST_EMPTY(&fec->nh_root) &&
605 MPLS_LIST_EMPTY(&fec->fs_root_ds)) {
606 return MPLS_BOOL_TRUE;
608 return MPLS_BOOL_FALSE;