More RSVP packet decode/encode
[mpls-ldp-portable.git] / ldp / ldp_fec.c
blob61d21344aeef08e6335db41c2d362026a4b637d7
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_session.h"
15 #include "ldp_inlabel.h"
16 #include "ldp_outlabel.h"
17 #include "ldp_global.h"
18 #include "ldp_label_mapping.h"
19 #include "ldp_label_request.h"
20 #include "ldp_label_abort.h"
21 #include "ldp_label_rel_with.h"
22 #include "mpls_mm_impl.h"
23 #include "mpls_policy_impl.h"
24 #include "mpls_trace_impl.h"
26 #if MPLS_USE_LSR
27 #include "lsr_cfg.h"
28 #else
29 #include "mpls_mpls_impl.h"
30 #endif
32 mpls_return_enum Recognize_New_Fec(ldp_global * g, mpls_fec * f)
34 ldp_session *peer = NULL;
35 ldp_session *nh_session = NULL;
36 ldp_attr *ds_attr = NULL;
37 ldp_attr *us_attr = NULL;
38 mpls_bool egress = MPLS_BOOL_FALSE;
39 ldp_addr *nh_addr;
40 ldp_outlabel *out;
42 LDP_ENTER(g->user_data, "Recognize_New_Fec");
45 * find the info about the next hop for this FEC
47 switch (ldp_get_next_hop_session_for_fec(g, f, &nh_addr, &nh_session)) {
48 case MPLS_SUCCESS:
49 break;
50 case MPLS_FAILURE:
52 * we found the route, but no next hop
54 egress = MPLS_BOOL_TRUE;
55 break;
56 case MPLS_NO_ROUTE:
57 return MPLS_FAILURE;
58 default:
59 MPLS_ASSERT(0);
62 if (nh_session) {
63 ds_attr = ldp_attr_find_downstream_state(g, nh_session, f,
64 LDP_LSP_STATE_MAP_RECV);
65 if (ds_attr && !ds_attr->outlabel) {
66 out = ldp_outlabel_create_complete(g, nh_session, nh_addr, ds_attr);
67 if (!out) {
68 return MPLS_FAILURE;
70 ds_attr->outlabel = out;
75 * for every peer except the nh hop peer, check to see if we need to
76 * send a mapping
78 peer = MPLS_LIST_HEAD(&g->session);
79 while (peer != NULL) { /* FEC.1 */
80 if ((peer->state != LDP_STATE_OPERATIONAL) ||
81 (nh_session && peer->index == nh_session->index)) {
82 goto next_peer;
84 /* have I already sent a mapping for FEC to peer */
85 if ((us_attr = ldp_attr_find_upstream_state(g, peer, f,
86 LDP_LSP_STATE_MAP_SENT))) {
87 /* yep, don't send another */
88 if (ds_attr) {
89 if (ldp_inlabel_add_outlabel(g, us_attr->inlabel,
90 ds_attr->outlabel) != MPLS_SUCCESS) {
91 return MPLS_FAILURE;
94 goto next_peer;
97 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
98 if (g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) {
99 us_attr =
100 ldp_attr_find_upstream_state(g, peer, f, LDP_LSP_STATE_REQ_RECV);
102 /* FEC.1.DUI3,4 */
103 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
104 MPLS_SUCCESS) {
105 if (!us_attr->in_tree) {
106 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
108 goto next_peer;
110 } else {
112 *LDP_CONTROL_ORDERED
115 if (ds_attr || egress == MPLS_BOOL_TRUE) { /* FEC.1.DUO2 */
116 if (!(us_attr = ldp_attr_create(f))) {
117 return MPLS_FAILURE;
119 /* FEC.1.DUO3-4 */
120 if ((egress == MPLS_BOOL_TRUE) && (mpls_policy_egress_check(
121 g->user_data, f, &f->nh) == MPLS_BOOL_TRUE)) {
122 goto next_peer;
125 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
126 MPLS_SUCCESS) {
127 return MPLS_FAILURE;
132 next_peer:
133 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
136 if (ds_attr) { /* FEC.2 */
137 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) ==
138 MPLS_FAILURE) { /* FEC.5 */
139 return MPLS_FAILURE;
141 return MPLS_SUCCESS;
145 * LDP_DISTRIBUTION_ONDEMAND
147 /* FEC.3 */
148 if (nh_session &&
149 nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND) {
150 /* assume we're always "request when needed" */
151 ds_attr = NULL;
152 if (ldp_label_request_for_xc(g, nh_session, f, NULL, &ds_attr) ==
153 MPLS_FAILURE) { /* FEC.4 */
154 return MPLS_FAILURE;
158 LDP_EXIT(g->user_data, "Recognize_New_Fec");
160 return MPLS_SUCCESS; /* FEC.6 */
163 mpls_return_enum Detect_Change_Fec_Next_Hop(ldp_global * g, mpls_fec * f,
164 ldp_session * nh_old)
166 ldp_session *peer = NULL;
167 ldp_attr *us_attr = NULL;
168 ldp_attr *ds_attr = NULL;
169 ldp_session *nh_session_new = NULL;
170 ldp_addr *nh_new = NULL;
171 mpls_return_enum result;
173 LDP_ENTER(g->user_data, "Detect_Change_Fec_Next_Hop");
175 result = ldp_get_next_hop_session_for_fec(g, f, &nh_new, &nh_session_new);
178 * NH 1-5 decide if we need to release an existing mapping
180 ds_attr =
181 ldp_attr_find_downstream_state(g, nh_old, f, LDP_LSP_STATE_MAP_RECV);
182 if (!ds_attr) { /* NH.1 */
183 goto Detect_Change_Fec_Next_Hop_6;
186 if (ds_attr->ingress == MPLS_BOOL_TRUE) {
188 #if MPLS_USE_LSR
189 lsr_ftn ftn;
190 ftn.outsegment_index = ds_attr->outlabel->info.handle;
191 memcpy(&ftn.fec, f, sizeof(mpls_fec));
192 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_DEL);
193 #else
194 mpls_mpls_fec2out_del(g->mpls_handle, f, &ds_attr->outlabel->info);
195 #endif
196 ds_attr->ingress = MPLS_BOOL_FALSE;
197 ds_attr->outlabel->merge_count--;
200 if (g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */
201 ldp_attr *us_temp;
202 us_attr = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
203 while (us_attr) {
204 /* need to walk the list in such a way as not to
205 * "pull the rug out from under me self"
207 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_attr, _ds_attr);
208 if (us_attr->state == LDP_LSP_STATE_MAP_SENT) {
209 ldp_inlabel_del_outlabel(g, us_attr->inlabel); /* NH.2 */
210 ldp_attr_del_us2ds(us_attr, ds_attr);
212 us_attr = us_temp;
214 goto Detect_Change_Fec_Next_Hop_6;
217 ldp_label_release_send(g, nh_old, ds_attr, LDP_NOTIF_NONE); /* NH.4 */
218 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* NH.2,5 */
220 Detect_Change_Fec_Next_Hop_6:
223 * NH 6-9 decides is we need to send a label request abort
225 ds_attr =
226 ldp_attr_find_downstream_state(g, nh_old, f, LDP_LSP_STATE_REQ_SENT);
227 if (ds_attr) { /* NH.6 */
228 if (g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */
229 /* NH.8,9 */
230 if (ldp_label_abort_send(g, nh_old, ds_attr) != MPLS_SUCCESS) {
231 return MPLS_FAILURE;
237 * NH 10-12 decides if we can use a mapping from our database
239 if (result != MPLS_SUCCESS) {
240 goto Detect_Change_Fec_Next_Hop_16;
243 ds_attr =
244 ldp_attr_find_downstream_state(g, nh_session_new, f, LDP_LSP_STATE_MAP_RECV);
245 if (!ds_attr) { /* NH.11 */
246 goto Detect_Change_Fec_Next_Hop_13;
249 if (ldp_label_mapping_process(g, nh_session_new, NULL, NULL, ds_attr, f) !=
250 MPLS_SUCCESS) { /* NH.12 */
251 return MPLS_FAILURE;
253 goto Detect_Change_Fec_Next_Hop_20;
255 Detect_Change_Fec_Next_Hop_13:
258 * NH 13-15 decides if we need to make a label request
260 if (nh_session_new->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND &&
261 g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) {
262 /* NH.14-15 */
263 if (ldp_label_request_for_xc(g, nh_session_new, f, NULL, &ds_attr) !=
264 MPLS_SUCCESS) {
265 return MPLS_FAILURE;
268 goto Detect_Change_Fec_Next_Hop_20;
270 Detect_Change_Fec_Next_Hop_16:
272 peer = MPLS_LIST_HEAD(&g->session);
273 while (peer) {
274 if (peer->state == LDP_STATE_OPERATIONAL) {
275 us_attr = ldp_attr_find_upstream_state(g, peer, f,
276 LDP_LSP_STATE_MAP_SENT);
277 if (us_attr) { /* NH.17 */
278 if (ldp_label_withdraw_send(g, peer, us_attr, LDP_NOTIF_NONE) !=
279 MPLS_SUCCESS) { /* NH.18 */
280 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
281 return MPLS_FAILURE;
285 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
288 Detect_Change_Fec_Next_Hop_20:
290 LDP_EXIT(g->user_data, "Detect_Change_Fec_Next_Hop");
292 return MPLS_SUCCESS;
295 ldp_fec *ldp_fec_create()
297 ldp_fec *fec = (ldp_fec *) mpls_malloc(sizeof(ldp_fec));
299 if (fec != NULL) {
300 memset(fec, 0, sizeof(ldp_fec));
301 MPLS_REFCNT_INIT(fec, 0);
302 MPLS_LIST_ELEM_INIT(fec, _global);
303 MPLS_LIST_ELEM_INIT(fec, _inlabel);
304 MPLS_LIST_ELEM_INIT(fec, _outlabel);
305 MPLS_LIST_ELEM_INIT(fec, _fec);
306 MPLS_LIST_ELEM_INIT(fec, _nh);
307 MPLS_LIST_INIT(&fec->fs_root_us, ldp_fs);
308 MPLS_LIST_INIT(&fec->fs_root_ds, ldp_fs);
309 fec->info.type = MPLS_FEC_NONE;
310 fec->info.nh.type = MPLS_NH_NONE;
311 fec->info.nh.attached = MPLS_BOOL_FALSE;
313 return fec;
316 void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b)
318 memcpy(&b->info, a, sizeof(mpls_fec));
321 ldp_fec *ldp_fec_create_host(mpls_inet_addr * host)
323 ldp_fec *fec = ldp_fec_create();
325 if (fec != NULL) {
326 fec->info.type = MPLS_FEC_HOST;
327 memcpy(&fec->info.u.host, host, sizeof(mpls_inet_addr));
329 return fec;
332 ldp_fec *ldp_fec_create_prefix(mpls_inet_addr * prefix, int prefix_len)
334 ldp_fec *fec = ldp_fec_create();
336 if (fec != NULL) {
337 fec->info.type = MPLS_FEC_PREFIX;
338 memcpy(&fec->info.u.prefix.network, prefix, sizeof(mpls_inet_addr));
339 fec->info.u.prefix.length = prefix_len;
341 return fec;
344 void ldp_fec_delete(ldp_fec * fec)
346 mpls_free(fec);
349 void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int i)
351 tlv->fecElArray[i].addressEl.addressFam = 1;
353 switch (lf->type) {
354 case MPLS_FEC_PREFIX:
355 tlv->fecElArray[i].addressEl.type = MPLS_PREFIX_FEC;
356 tlv->fecElArray[i].addressEl.preLen = lf->u.prefix.length;
357 tlv->fecElArray[i].addressEl.address = lf->u.prefix.network.u.ipv4;
358 tlv->fecElemTypes[i] = MPLS_PREFIX_FEC;
359 break;
360 case MPLS_FEC_HOST:
361 tlv->fecElArray[i].addressEl.type = MPLS_HOSTADR_FEC;
362 tlv->fecElArray[i].addressEl.preLen = MPLS_IPv4LEN;
363 tlv->fecElArray[i].addressEl.address = lf->u.host.u.ipv4;
364 tlv->fecElemTypes[i] = MPLS_HOSTADR_FEC;
365 break;
366 default:
367 MPLS_ASSERT(0);
371 void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int i, mpls_fec * lf) {
372 switch (tlv->fecElemTypes[i]) {
373 case MPLS_PREFIX_FEC:
374 lf->type = MPLS_FEC_PREFIX;
375 lf->u.prefix.length = tlv->fecElArray[i].addressEl.preLen;
376 lf->u.prefix.network.u.ipv4 = tlv->fecElArray[i].addressEl.address;
377 lf->u.prefix.network.type = MPLS_FAMILY_IPV4;
378 break;
379 case MPLS_HOSTADR_FEC:
380 lf->type = MPLS_FEC_HOST;
381 lf->u.host.u.ipv4 = tlv->fecElArray[i].addressEl.address;
382 lf->u.host.type = MPLS_FAMILY_IPV4;
383 break;
384 default:
385 MPLS_ASSERT(0);