LCOV - code coverage report
Current view: top level - vnet/fib - fib_path_ext.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 156 162 96.3 %
Date: 2023-07-05 22:20:52 Functions: 17 17 100.0 %

          Line data    Source code
       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           4 : format_fib_path_ext (u8 * s, va_list * args)
      32             : {
      33             :     fib_path_ext_t *path_ext;
      34             :     u32 ii;
      35             : 
      36           4 :     path_ext = va_arg (*args, fib_path_ext_t *);
      37             : 
      38           4 :     s = format(s, "path:%d ", path_ext->fpe_path_index);
      39             : 
      40           4 :     switch (path_ext->fpe_type)
      41             :     {
      42           2 :     case FIB_PATH_EXT_MPLS: {
      43             :         fib_path_ext_mpls_attr_t attr;
      44             : 
      45           2 :         if (path_ext->fpe_mpls_flags)
      46             :         {
      47           1 :             s = format(s, "mpls-flags:[");
      48             : 
      49           2 :             FOR_EACH_PATH_EXT_MPLS_ATTR(attr)
      50             :             {
      51           1 :                 if ((1<<attr) & path_ext->fpe_mpls_flags) {
      52           1 :                     s = format(s, "%s", fib_path_ext_mpls_flags_names[attr]);
      53             :                 }
      54             :             }
      55           1 :             s = format(s, "]");
      56             :         }
      57           2 :         s = format(s, " labels:[");
      58           6 :         for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++)
      59             :         {
      60           4 :             s = format(s, "[%U]",
      61             :                        format_fib_mpls_label,
      62           4 :                        &path_ext->fpe_path.frp_label_stack[ii]);
      63             :         }
      64           2 :         s = format(s, "]");
      65           2 :         break;
      66             :     }
      67           2 :     case FIB_PATH_EXT_ADJ: {
      68             :         fib_path_ext_adj_attr_t attr;
      69             : 
      70           2 :         if (path_ext->fpe_adj_flags)
      71             :         {
      72           2 :             s = format(s, "adj-flags:[");
      73           4 :             FOR_EACH_PATH_EXT_ADJ_ATTR(attr)
      74             :             {
      75           2 :                 if ((1<<attr) & path_ext->fpe_adj_flags)
      76             :                 {
      77           2 :                     s = format(s, "%s", fib_path_ext_adj_flags_names[attr]);
      78             :                 }
      79             :             }
      80           2 :             s = format(s, "]");
      81             :         }
      82           2 :         break;
      83             :     }
      84             :     }
      85           4 :     return (s);
      86             : }
      87             : 
      88             : int
      89        5469 : fib_path_ext_cmp (fib_path_ext_t *path_ext,
      90             :                   const fib_route_path_t *rpath)
      91             : {
      92        5469 :     return (fib_route_path_cmp(&path_ext->fpe_path, rpath));
      93             : }
      94             : 
      95             : static fib_path_list_walk_rc_t
      96        9950 : fib_path_ext_match (fib_node_index_t pl_index,
      97             :                     fib_node_index_t path_index,
      98             :                     void *ctx)
      99             : {
     100        9950 :     fib_path_ext_t *path_ext = ctx;
     101             : 
     102        9950 :     if (!fib_path_cmp_w_route_path(path_index,
     103        9950 :                                    &path_ext->fpe_path))
     104             :     {
     105        9870 :         path_ext->fpe_path_index = path_index;
     106        9870 :         return (FIB_PATH_LIST_WALK_STOP);
     107             :     }
     108          80 :     return (FIB_PATH_LIST_WALK_CONTINUE);
     109             : }
     110             : 
     111             : void
     112        9870 : 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        9870 :     path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
     119        9870 :     fib_path_list_walk(path_list_index,
     120             :                        fib_path_ext_match,
     121             :                        path_ext);
     122        9870 : }
     123             : 
     124             : static void
     125        9850 : 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        9850 :     path_ext->fpe_path = *rpath;
     131        9850 :     path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
     132        9850 :     path_ext->fpe_adj_flags = FIB_PATH_EXT_ADJ_FLAG_NONE;
     133        9850 :     path_ext->fpe_type = ext_type;
     134             : 
     135        9850 :     fib_path_ext_resolve(path_ext, path_list_index);
     136        9850 : }
     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        3048 : fib_path_ext_is_imp_null (fib_path_ext_t *path_ext)
     145             : {
     146        5738 :     return ((1 == vec_len(path_ext->fpe_label_stack)) &&
     147        2690 :             ((MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0].fml_value) ||
     148        2635 :              (MPLS_LABEL_POP == path_ext->fpe_label_stack[0].fml_value)));
     149             : }
     150             : 
     151             : mpls_label_dpo_flags_t
     152        1766 : fib_path_ext_mpls_flags_to_mpls_label (fib_path_ext_mpls_flags_t fpe_flags)
     153             : {
     154        1766 :     mpls_label_dpo_flags_t ml_flags = MPLS_LABEL_DPO_FLAG_NONE;
     155             : 
     156        1766 :     if (fpe_flags &FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR)
     157             :     {
     158         344 :         ml_flags |= MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
     159             :     }
     160             : 
     161        1766 :     return (ml_flags);
     162             : }
     163             : 
     164             : load_balance_path_t *
     165        1801 : 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        1801 :     if (!fib_path_is_resolved(path_ext->fpe_path_index))
     174           0 :         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        1801 :     switch (child_fct)
     182             :     {
     183          67 :     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          67 :         if (fib_path_ext_is_imp_null(path_ext))
     191             :         {
     192          15 :             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          52 :             parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
     201             :         }
     202          67 :         break;
     203             :     }
     204        1182 :     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
     205             :     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
     206        1182 :         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           9 :             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        1173 :             parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
     221             :         }
     222        1182 :         break;
     223         235 :     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
     224         235 :         parent_fct = child_fct;
     225         235 :         break;
     226         317 :     case FIB_FORW_CHAIN_TYPE_ETHERNET:
     227         317 :         parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
     228         317 :         break;
     229           0 :     default:
     230           0 :         return (nhs);
     231             :         break;
     232             :     }
     233             : 
     234        1801 :     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        1801 :     fib_path_contribute_forwarding(path_ext->fpe_path_index,
     242             :                                    parent_fct,
     243             :                                    payload_proto,
     244             :                                    &via_dpo);
     245             : 
     246        3602 :     if (dpo_is_drop(&via_dpo) ||
     247        1801 :         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        1799 :         vec_add2(nhs, nh, 1);
     257        1799 :         nh->path_weight = fib_path_get_weight(path_ext->fpe_path_index);
     258        1799 :         nh->path_index = path_ext->fpe_path_index;
     259        1799 :         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        1799 :         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        1766 :             dpo_id_t parent = DPO_INVALID;
     273             :             dpo_proto_t chain_proto;
     274             :             mpls_eos_bit_t eos;
     275             : 
     276        1766 :             eos = (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS ?
     277        1766 :                    MPLS_NON_EOS :
     278             :                    MPLS_EOS);
     279        1766 :             chain_proto = fib_forw_chain_type_to_dpo_proto(child_fct);
     280             : 
     281        1766 :             dpo_copy(&parent, &nh->path_dpo);
     282        1766 :             mpls_label_dpo_create(path_ext->fpe_label_stack,
     283             :                                   eos,
     284             :                                   chain_proto,
     285        1766 :                                   fib_path_ext_mpls_flags_to_mpls_label(
     286             :                                       path_ext->fpe_mpls_flags),
     287             :                                   &parent,
     288        1766 :                                   &nh->path_dpo);
     289             : 
     290        1766 :             dpo_reset(&parent);
     291             :         }
     292          33 :         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          15 :             fib_path_stack_mpls_disp(nh->path_index,
     298          15 :                                      fib_forw_chain_type_to_dpo_proto(parent_fct),
     299          15 :                                      path_ext->fpe_label_stack[0].fml_mode,
     300          15 :                                      &nh->path_dpo);
     301             :         }
     302             :     }
     303        1801 :     dpo_reset(&via_dpo);
     304             : 
     305        1801 :     return (nhs);
     306             : }
     307             : 
     308             : fib_path_ext_t *
     309       15294 : 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       15365 :     vec_foreach(path_ext, list->fpel_exts)
     316             :     {
     317       10918 :         if ((path_ext->fpe_type == ext_type) &&
     318        5459 :             !fib_path_ext_cmp(path_ext, rpath) )
     319             :         {
     320        5388 :             return (path_ext);
     321             :         }
     322             :     }
     323        9906 :     return (NULL);
     324             : }
     325             : 
     326             : fib_path_ext_t *
     327      331689 : 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      331689 :     if (NULL != list)
     333             :     {
     334      330722 :         vec_foreach(path_ext, list->fpel_exts)
     335             :         {
     336      107725 :             if (path_ext->fpe_path_index == path_index)
     337             :             {
     338      102686 :                 return (path_ext);
     339             :             }
     340             :         }
     341             :     }
     342      229003 :     return (NULL);
     343             : }
     344             : 
     345             : 
     346             : fib_path_ext_t *
     347        9840 : 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        9840 :     path_ext = fib_path_ext_list_find(list, ext_type, rpath);
     355             : 
     356        9840 :     if (NULL == path_ext)
     357             :     {
     358        9840 :         vec_add2(list->fpel_exts, path_ext, 1);
     359        9840 :         fib_path_ext_init(path_ext, path_list_index, ext_type, rpath);
     360             :     }
     361             : 
     362        9840 :     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         263 : 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         263 :     int i = 0;
     380             : 
     381         263 :     if (0 == fib_path_ext_list_length(list))
     382             :     {
     383         253 :         return (fib_path_ext_list_push_back(list, path_list_index,
     384             :                                             ext_type, rpath));
     385             :     }
     386             : 
     387          10 :     fib_path_ext_init(&new_path_ext, path_list_index, ext_type, rpath);
     388             : 
     389          17 :     vec_foreach(path_ext, list->fpel_exts)
     390             :     {
     391          10 :         int res = fib_path_ext_cmp(path_ext, rpath);
     392             : 
     393          10 :         if (0 == res)
     394             :         {
     395             :             /*
     396             :              * don't add duplicate extensions. modify instead
     397             :              */
     398           0 :             vec_free(path_ext->fpe_label_stack);
     399           0 :             *path_ext = new_path_ext;
     400           0 :             goto done;
     401             :         }
     402          10 :         else if (res < 0)
     403             :         {
     404           7 :             i++;
     405             :         }
     406             :         else
     407             :         {
     408           3 :             break;
     409             :         }
     410             :     }
     411          10 :     vec_insert_elts(list->fpel_exts, &new_path_ext, 1, i);
     412          10 : done:
     413          10 :     return (&(list->fpel_exts[i]));
     414             : }
     415             : 
     416             : void
     417        5806 : 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        5826 :     vec_foreach(path_ext, list->fpel_exts)
     423             :     {
     424          20 :         fib_path_ext_resolve(path_ext, path_list_index);
     425             :     };
     426        5806 : }
     427             : 
     428             : void
     429        5454 : 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        5454 :     path_ext = fib_path_ext_list_find(list, ext_type, rpath);
     436             : 
     437        5454 :     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        5388 :         vec_free(path_ext->fpe_label_stack);
     444        5388 :         vec_delete(list->fpel_exts, 1, (path_ext - list->fpel_exts));
     445             :     }
     446        5454 : }
     447             : 
     448             : void
     449       50286 : fib_path_ext_list_flush (fib_path_ext_list_t *list)
     450             : {
     451             :     fib_path_ext_t *path_ext;
     452             : 
     453       50566 :     vec_foreach(path_ext, list->fpel_exts)
     454             :     {
     455         280 :         vec_free(path_ext->fpe_label_stack);
     456             :     };
     457       50286 :     vec_free(list->fpel_exts);
     458       50286 :     list->fpel_exts = NULL;
     459       50286 : }
     460             : 
     461             : u8*
     462         217 : 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         217 :     list = va_arg (*args, fib_path_ext_list_t *);
     468             : 
     469         217 :     if (fib_path_ext_list_length(list))
     470             :     {
     471           4 :         s = format(s, "    Extensions:");
     472           8 :         vec_foreach(path_ext, list->fpel_exts)
     473             :         {
     474           4 :             s = format(s, "\n     %U", format_fib_path_ext, path_ext);
     475             :         };
     476             :     }
     477             : 
     478         217 :     return (s);
     479             : }
     480             : 
     481             : int
     482         487 : fib_path_ext_list_length (const fib_path_ext_list_t *list)
     483             : {
     484         487 :     return (vec_len(list->fpel_exts));
     485             : }

Generated by: LCOV version 1.14