vlib: fix use of RTLD_DEEPBIND for musl
[vpp.git] / src / vnet / fib / fib_path_ext.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/mpls/mpls.h>
17 #include <vnet/dpo/mpls_label_dpo.h>
18 #include <vnet/dpo/load_balance.h>
19 #include <vnet/dpo/drop_dpo.h>
20
21 #include <vnet/fib/fib_path_ext.h>
22 #include <vnet/fib/fib_entry_src.h>
23 #include <vnet/fib/fib_path.h>
24 #include <vnet/fib/fib_path_list.h>
25 #include <vnet/fib/fib_internal.h>
26
27 const char *fib_path_ext_adj_flags_names[] = FIB_PATH_EXT_ADJ_ATTR_NAMES;
28 const char *fib_path_ext_mpls_flags_names[] = FIB_PATH_EXT_MPLS_ATTR_NAMES;
29
30 u8 *
31 format_fib_path_ext (u8 * s, va_list * args)
32 {
33     fib_path_ext_t *path_ext;
34     u32 ii;
35
36     path_ext = va_arg (*args, fib_path_ext_t *);
37
38     s = format(s, "path:%d ", path_ext->fpe_path_index);
39
40     switch (path_ext->fpe_type)
41     {
42     case FIB_PATH_EXT_MPLS: {
43         fib_path_ext_mpls_attr_t attr;
44
45         if (path_ext->fpe_mpls_flags)
46         {
47             s = format(s, "mpls-flags:[");
48
49             FOR_EACH_PATH_EXT_MPLS_ATTR(attr)
50             {
51                 if ((1<<attr) & path_ext->fpe_mpls_flags) {
52                     s = format(s, "%s", fib_path_ext_mpls_flags_names[attr]);
53                 }
54             }
55             s = format(s, "]");
56         }
57         s = format(s, " labels:[");
58         for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++)
59         {
60             s = format(s, "[%U]",
61                        format_fib_mpls_label,
62                        &path_ext->fpe_path.frp_label_stack[ii]);
63         }
64         s = format(s, "]");
65         break;
66     }
67     case FIB_PATH_EXT_ADJ: {
68         fib_path_ext_adj_attr_t attr;
69
70         if (path_ext->fpe_adj_flags)
71         {
72             s = format(s, "adj-flags:[");
73             FOR_EACH_PATH_EXT_ADJ_ATTR(attr)
74             {
75                 if ((1<<attr) & path_ext->fpe_adj_flags)
76                 {
77                     s = format(s, "%s", fib_path_ext_adj_flags_names[attr]);
78                 }
79             }
80             s = format(s, "]");
81         }
82         break;
83     }
84     }
85     return (s);
86 }
87
88 int
89 fib_path_ext_cmp (fib_path_ext_t *path_ext,
90                   const fib_route_path_t *rpath)
91 {
92     return (fib_route_path_cmp(&path_ext->fpe_path, rpath));
93 }
94
95 static fib_path_list_walk_rc_t
96 fib_path_ext_match (fib_node_index_t pl_index,
97                     fib_node_index_t path_index,
98                     void *ctx)
99 {
100     fib_path_ext_t *path_ext = ctx;
101
102     if (!fib_path_cmp_w_route_path(path_index,
103                                    &path_ext->fpe_path))
104     {
105         path_ext->fpe_path_index = path_index;
106         return (FIB_PATH_LIST_WALK_STOP);
107     }
108     return (FIB_PATH_LIST_WALK_CONTINUE);
109 }
110
111 void
112 fib_path_ext_resolve (fib_path_ext_t *path_ext,
113                       fib_node_index_t path_list_index)
114 {
115     /*
116      * Find the path on the path list that this is an extension for
117      */
118     path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
119     fib_path_list_walk(path_list_index,
120                        fib_path_ext_match,
121                        path_ext);
122 }
123
124 static void
125 fib_path_ext_init (fib_path_ext_t *path_ext,
126                    fib_node_index_t path_list_index,
127                    fib_path_ext_type_t ext_type,
128                    const fib_route_path_t *rpath)
129 {
130     path_ext->fpe_path = *rpath;
131     path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
132     path_ext->fpe_adj_flags = FIB_PATH_EXT_ADJ_FLAG_NONE;
133     path_ext->fpe_type = ext_type;
134
135     fib_path_ext_resolve(path_ext, path_list_index);
136 }
137
138 /**
139  * @brief Return true if the label stack is implicit null
140  * imp-null and pop equate to the same this as this level -
141  * the label is coming off.
142  */
143 static int
144 fib_path_ext_is_imp_null (fib_path_ext_t *path_ext)
145 {
146     return ((1 == vec_len(path_ext->fpe_label_stack)) &&
147             ((MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0].fml_value) ||
148              (MPLS_LABEL_POP == path_ext->fpe_label_stack[0].fml_value)));
149 }
150
151 mpls_label_dpo_flags_t
152 fib_path_ext_mpls_flags_to_mpls_label (fib_path_ext_mpls_flags_t fpe_flags)
153 {
154     mpls_label_dpo_flags_t ml_flags = MPLS_LABEL_DPO_FLAG_NONE;
155
156     if (fpe_flags &FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR)
157     {
158         ml_flags |= MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
159     }
160
161     return (ml_flags);
162 }
163
164 load_balance_path_t *
165 fib_path_ext_stack (fib_path_ext_t *path_ext,
166                     dpo_proto_t payload_proto,
167                     fib_forward_chain_type_t child_fct,
168                     load_balance_path_t *nhs)
169 {
170     fib_forward_chain_type_t parent_fct;
171     load_balance_path_t *nh;
172
173     if (!fib_path_is_resolved(path_ext->fpe_path_index))
174         return (nhs);
175
176     /*
177      * Since we are stacking this path-extension, it must have a valid out
178      * label. From the chain type request by the child, determine what
179      * chain type we will request from the parent.
180      */
181     switch (child_fct)
182     {
183     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
184     {
185         /*
186          * The EOS chain is a tricky since, when the path has an imp NULL one cannot know
187          * the adjacency to link to without knowing what the packets payload protocol
188          * will be once the label is popped.
189          */
190         if (fib_path_ext_is_imp_null(path_ext))
191         {
192             parent_fct = fib_forw_chain_type_from_dpo_proto(payload_proto);
193         }
194         else
195         {
196             /*
197              * we have a label to stack. packets will thus be labelled when
198              * they encounter the child, ergo, non-eos.
199              */
200             parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
201         }
202         break;
203     }
204     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
205     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
206         if (fib_path_ext_is_imp_null(path_ext))
207         {
208             /*
209              * implicit-null label for the eos or IP chain, need to pick up
210              * the IP adj
211              */
212             parent_fct = child_fct;
213         }
214         else
215         {
216             /*
217              * we have a label to stack. packets will thus be labelled when
218              * they encounter the child, ergo, non-eos.
219              */
220             parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
221         }
222         break;
223     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
224         parent_fct = child_fct;
225         break;
226     case FIB_FORW_CHAIN_TYPE_ETHERNET:
227         parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
228         break;
229     default:
230         return (nhs);
231         break;
232     }
233
234     dpo_id_t via_dpo = DPO_INVALID;
235
236     /*
237      * The next object in the graph after the imposition of the label
238      * will be the DPO contributed by the path through which the packets
239      * are to be sent. We stack the MPLS Label DPO on this path DPO
240      */
241     fib_path_contribute_forwarding(path_ext->fpe_path_index,
242                                    parent_fct,
243                                    payload_proto,
244                                    &via_dpo);
245
246     if (dpo_is_drop(&via_dpo) ||
247         load_balance_is_drop(&via_dpo))
248     {
249         /*
250          * don't stack a path extension on a drop. doing so will create
251          * a LB bucket entry on drop, and we will lose a percentage of traffic.
252          */
253     }
254     else
255     {
256         vec_add2(nhs, nh, 1);
257         nh->path_weight = fib_path_get_weight(path_ext->fpe_path_index);
258         nh->path_index = path_ext->fpe_path_index;
259         dpo_copy(&nh->path_dpo, &via_dpo);
260
261         /*
262          * The label is stackable for this chain type
263          * construct the mpls header that will be imposed in the data-path
264          */
265         if (!fib_path_ext_is_imp_null(path_ext))
266         {
267             /*
268              * we use the parent protocol for the label so that
269              * we pickup the correct MPLS imposition nodes to do
270              * ip[46] processing.
271              */
272             dpo_id_t parent = DPO_INVALID;
273             dpo_proto_t chain_proto;
274             mpls_eos_bit_t eos;
275
276             eos = (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS ?
277                    MPLS_NON_EOS :
278                    MPLS_EOS);
279             chain_proto = fib_forw_chain_type_to_dpo_proto(child_fct);
280
281             dpo_copy(&parent, &nh->path_dpo);
282             mpls_label_dpo_create(path_ext->fpe_label_stack,
283                                   eos,
284                                   chain_proto,
285                                   fib_path_ext_mpls_flags_to_mpls_label(
286                                       path_ext->fpe_mpls_flags),
287                                   &parent,
288                                   &nh->path_dpo);
289
290             dpo_reset(&parent);
291         }
292         else if (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_EOS)
293         {
294             /*
295              * MPLS EOS packets using an imp-null. Insert the disposition.
296              */
297             fib_path_stack_mpls_disp(nh->path_index,
298                                      fib_forw_chain_type_to_dpo_proto(parent_fct),
299                                      path_ext->fpe_label_stack[0].fml_mode,
300                                      &nh->path_dpo);
301         }
302     }
303     dpo_reset(&via_dpo);
304
305     return (nhs);
306 }
307
308 fib_path_ext_t *
309 fib_path_ext_list_find (const fib_path_ext_list_t *list,
310                         fib_path_ext_type_t ext_type,
311                         const fib_route_path_t *rpath)
312 {
313     fib_path_ext_t *path_ext;
314
315     vec_foreach(path_ext, list->fpel_exts)
316     {
317         if ((path_ext->fpe_type == ext_type) &&
318             !fib_path_ext_cmp(path_ext, rpath) )
319         {
320             return (path_ext);
321         }
322     }
323     return (NULL);
324 }
325
326 fib_path_ext_t *
327 fib_path_ext_list_find_by_path_index (const fib_path_ext_list_t *list,
328                                       fib_node_index_t path_index)
329 {
330     fib_path_ext_t *path_ext;
331
332     if (NULL != list)
333     {
334         vec_foreach(path_ext, list->fpel_exts)
335         {
336             if (path_ext->fpe_path_index == path_index)
337             {
338                 return (path_ext);
339             }
340         }
341     }
342     return (NULL);
343 }
344
345
346 fib_path_ext_t *
347 fib_path_ext_list_push_back (fib_path_ext_list_t *list,
348                              fib_node_index_t path_list_index,
349                              fib_path_ext_type_t ext_type,
350                              const fib_route_path_t *rpath)
351 {
352     fib_path_ext_t *path_ext;
353
354     path_ext = fib_path_ext_list_find(list, ext_type, rpath);
355
356     if (NULL == path_ext)
357     {
358         vec_add2(list->fpel_exts, path_ext, 1);
359         fib_path_ext_init(path_ext, path_list_index, ext_type, rpath);
360     }
361
362     return (path_ext);
363 }
364
365 /*
366  * insert, sorted, a path extension to the entry's list.
367  * It's not strictly necessary to sort the path extensions, since each
368  * extension has the path index to which it resolves. However, by being
369  * sorted the load-balance produced has a deterministic order, not an order
370  * based on the sequence of extension additions. this is a considerable benefit.
371  */
372 fib_path_ext_t *
373 fib_path_ext_list_insert (fib_path_ext_list_t *list,
374                           fib_node_index_t path_list_index,
375                           fib_path_ext_type_t ext_type,
376                           const fib_route_path_t *rpath)
377 {
378     fib_path_ext_t new_path_ext, *path_ext;
379     int i = 0;
380
381     if (0 == fib_path_ext_list_length(list))
382     {
383         return (fib_path_ext_list_push_back(list, path_list_index,
384                                             ext_type, rpath));
385     }
386
387     fib_path_ext_init(&new_path_ext, path_list_index, ext_type, rpath);
388
389     vec_foreach(path_ext, list->fpel_exts)
390     {
391         int res = fib_path_ext_cmp(path_ext, rpath);
392
393         if (0 == res)
394         {
395             /*
396              * don't add duplicate extensions. modify instead
397              */
398             vec_free(path_ext->fpe_label_stack);
399             *path_ext = new_path_ext;
400             goto done;
401         }
402         else if (res < 0)
403         {
404             i++;
405         }
406         else
407         {
408             break;
409         }
410     }
411     vec_insert_elts(list->fpel_exts, &new_path_ext, 1, i);
412 done:
413     return (&(list->fpel_exts[i]));
414 }
415
416 void
417 fib_path_ext_list_resolve (fib_path_ext_list_t *list,
418                            fib_node_index_t path_list_index)
419 {
420     fib_path_ext_t *path_ext;
421
422     vec_foreach(path_ext, list->fpel_exts)
423     {
424         fib_path_ext_resolve(path_ext, path_list_index);
425     };
426 }
427
428 void
429 fib_path_ext_list_remove (fib_path_ext_list_t *list,
430                           fib_path_ext_type_t ext_type,
431                           const fib_route_path_t *rpath)
432 {
433     fib_path_ext_t *path_ext;
434
435     path_ext = fib_path_ext_list_find(list, ext_type, rpath);
436
437     if (NULL != path_ext)
438     {
439         /*
440          * delete the element moving the remaining elements down 1 position.
441          * this preserves the sorted order.
442          */
443         vec_free(path_ext->fpe_label_stack);
444         vec_delete(list->fpel_exts, 1, (path_ext - list->fpel_exts));
445     }
446 }
447
448 void
449 fib_path_ext_list_flush (fib_path_ext_list_t *list)
450 {
451     fib_path_ext_t *path_ext;
452
453     vec_foreach(path_ext, list->fpel_exts)
454     {
455         vec_free(path_ext->fpe_label_stack);
456     };
457     vec_free(list->fpel_exts);
458     list->fpel_exts = NULL;
459 }
460
461 u8*
462 format_fib_path_ext_list (u8 * s, va_list * args)
463 {
464     fib_path_ext_list_t *list;
465     fib_path_ext_t *path_ext;
466
467     list = va_arg (*args, fib_path_ext_list_t *);
468
469     if (fib_path_ext_list_length(list))
470     {
471         s = format(s, "    Extensions:");
472         vec_foreach(path_ext, list->fpel_exts)
473         {
474             s = format(s, "\n     %U", format_fib_path_ext, path_ext);
475         };
476     }
477
478     return (s);
479 }
480
481 int
482 fib_path_ext_list_length (const fib_path_ext_list_t *list)
483 {
484     return (vec_len(list->fpel_exts));
485 }