LCOV - code coverage report
Current view: top level - plugins/nsh/nsh-md2-ioam - nsh_md2_ioam.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 5 151 3.3 %
Date: 2023-10-26 01:39:38 Functions: 3 14 21.4 %

          Line data    Source code
       1             : /*
       2             :  * nsh_md2_ioam.c - NSH iOAM functions for MD type 2
       3             :  *
       4             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vnet/vnet.h>
      19             : #include <vnet/plugin/plugin.h>
      20             : #include <nsh/nsh.h>
      21             : #include <nsh/nsh_packet.h>
      22             : #include <vnet/ip/ip.h>
      23             : #include <nsh/nsh-md2-ioam/nsh_md2_ioam.h>
      24             : 
      25             : #include <vlibapi/api.h>
      26             : #include <vlibmemory/api.h>
      27             : 
      28             : #include <vnet/fib/ip6_fib.h>
      29             : #include <vnet/fib/ip4_fib.h>
      30             : #include <vnet/fib/fib_entry.h>
      31             : 
      32             : /* define message structures */
      33             : #define vl_typedefs
      34             : #include <nsh/nsh.api.h>
      35             : #undef vl_typedefs
      36             : 
      37             : /* define generated endian-swappers */
      38             : #define vl_endianfun
      39             : #include <nsh/nsh.api.h>
      40             : #undef vl_endianfun
      41             : 
      42             : nsh_md2_ioam_main_t nsh_md2_ioam_main;
      43             : 
      44             : static void
      45           0 : nsh_md2_ioam_set_clear_output_feature_on_intf (vlib_main_t * vm,
      46             :                                                     u32 sw_if_index0,
      47             :                                                     u8 is_add)
      48             : {
      49             : 
      50             : 
      51             : 
      52           0 :   vnet_feature_enable_disable ("ip4-output",
      53             :                                "nsh-md2-ioam-encap-transit",
      54             :                                sw_if_index0, is_add,
      55             :                                0 /* void *feature_config */ ,
      56             :                                0 /* u32 n_feature_config_bytes */ );
      57           0 :   return;
      58             : }
      59             : 
      60             : void
      61           0 : nsh_md2_ioam_clear_output_feature_on_all_intfs (vlib_main_t * vm)
      62             : {
      63           0 :   vnet_sw_interface_t *si = 0;
      64           0 :   vnet_main_t *vnm = vnet_get_main ();
      65           0 :   vnet_interface_main_t *im = &vnm->interface_main;
      66             : 
      67           0 :   pool_foreach (si, im->sw_interfaces)
      68             :                                          {
      69           0 :                                          nsh_md2_ioam_set_clear_output_feature_on_intf
      70             :                                          (vm, si->sw_if_index, 0);
      71             :                                          }
      72           0 :   return;
      73             : }
      74             : 
      75             : 
      76             : extern fib_forward_chain_type_t
      77             : fib_entry_get_default_chain_type (const fib_entry_t * fib_entry);
      78             : 
      79             : int
      80           0 : nsh_md2_ioam_enable_disable_for_dest (vlib_main_t * vm,
      81             :                                            ip46_address_t dst_addr,
      82             :                                            u32 outer_fib_index,
      83             :                                            u8 is_ipv4, u8 is_add)
      84             : {
      85           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
      86           0 :   u32 fib_index0 = 0;
      87             : 
      88           0 :   fib_node_index_t fei = ~0;
      89           0 :   u32 *sw_if_index0 = NULL;
      90             : #if 0
      91             :   fib_entry_t *fib_entry;
      92             :   u32 adj_index0;
      93             :   ip_adjacency_t *adj0;
      94             :   load_balance_t *lb_m, *lb_b;
      95             :   const dpo_id_t *dpo0, *dpo1;
      96             :   u32 i, j, k;
      97             : #endif
      98           0 :   u32 *intf_list = NULL;
      99             :   fib_prefix_t fib_prefix;
     100             : 
     101           0 :   if (is_ipv4)
     102             :     {
     103           0 :       clib_memset (&fib_prefix, 0, sizeof (fib_prefix_t));
     104           0 :       fib_prefix.fp_len = 32;
     105           0 :       fib_prefix.fp_proto = FIB_PROTOCOL_IP4;
     106             : #define  TRANSIT_UNIT_TEST_HACK 1
     107             : #ifdef TRANSIT_UNIT_TEST_HACK
     108           0 :       clib_memset(&dst_addr, 0, sizeof(dst_addr));
     109           0 :       dst_addr.ip4.as_u32 = clib_net_to_host_u32(0x14020102);
     110             : #endif
     111           0 :       fib_prefix.fp_addr = dst_addr;
     112             :     }
     113             :   else
     114             :     {
     115           0 :       return 0;
     116             :     }
     117             : 
     118           0 :   fei = fib_table_lookup (fib_index0, &fib_prefix);
     119             : #if 0
     120             :   fib_entry = fib_entry_get (fei);
     121             : 
     122             : 
     123             :   if (!dpo_id_is_valid (&fib_entry->fe_lb))
     124             :     {
     125             :       return (-1);
     126             :     }
     127             : 
     128             :   lb_m = load_balance_get (fib_entry->fe_lb.dpoi_index);
     129             : 
     130             :   for (i = 0; i < lb_m->lb_n_buckets; i++)
     131             :     {
     132             :       dpo0 = load_balance_get_bucket_i (lb_m, i);
     133             : 
     134             :       if (dpo0->dpoi_type == DPO_LOAD_BALANCE ||
     135             :           dpo0->dpoi_type == DPO_ADJACENCY)
     136             :         {
     137             :           if (dpo0->dpoi_type == DPO_ADJACENCY)
     138             :             {
     139             :               k = 1;
     140             :             }
     141             :           else
     142             :             {
     143             :               lb_b = load_balance_get (dpo0->dpoi_index);
     144             :               k = lb_b->lb_n_buckets;
     145             :             }
     146             : 
     147             :           for (j = 0; j < k; j++)
     148             :             {
     149             :               if (dpo0->dpoi_type == DPO_ADJACENCY)
     150             :                 {
     151             :                   dpo1 = dpo0;
     152             :                 }
     153             :               else
     154             :                 {
     155             :                   dpo1 = load_balance_get_bucket_i (lb_b, j);
     156             :                 }
     157             : 
     158             :               if (dpo1->dpoi_type == DPO_ADJACENCY)
     159             :                 {
     160             :                   adj_index0 = dpo1->dpoi_index;
     161             : 
     162             :                   if (ADJ_INDEX_INVALID == adj_index0)
     163             :                     {
     164             :                       continue;
     165             :                     }
     166             : 
     167             :                   adj0 =
     168             :                     ip_get_adjacency (&(ip4_main.lookup_main), adj_index0);
     169             :                   sw_if_index0 = adj0->rewrite_header.sw_if_index;
     170             : 
     171             :                   if (~0 == sw_if_index0)
     172             :                     {
     173             :                       continue;
     174             :                     }
     175             : 
     176             : 
     177             :                   if (is_add)
     178             :                     {
     179             :                       vnet_feature_enable_disable ("ip4-output",
     180             :                                                    "nsh-md2-ioam-encap-transit",
     181             :                                                    sw_if_index0, is_add, 0,
     182             :                                                    /* void *feature_config */
     183             :                                                    0    /* u32 n_feature_config_bytes */
     184             :                         );
     185             : 
     186             :                       vec_validate_init_empty (hm->bool_ref_by_sw_if_index,
     187             :                                                sw_if_index0, ~0);
     188             :                       hm->bool_ref_by_sw_if_index[sw_if_index0] = 1;
     189             :                     }
     190             :                   else
     191             :                     {
     192             :                       hm->bool_ref_by_sw_if_index[sw_if_index0] = ~0;
     193             :                     }
     194             :                 }
     195             :             }
     196             :         }
     197             :     }
     198             : #else
     199             : 
     200             : u32 fib_path_get_resolving_interface (fib_node_index_t path_index);
     201           0 :     vec_add1(intf_list, fib_path_get_resolving_interface(fei));
     202           0 :     vec_foreach(sw_if_index0, intf_list)
     203           0 :     if (is_add)
     204             :       {
     205           0 :         vnet_feature_enable_disable ("ip4-output",
     206             :                          "nsh-md2-ioam-encap-transit",
     207             :                          *sw_if_index0, is_add, 0,
     208             :                          /* void *feature_config */
     209             :                          0    /* u32 n_feature_config_bytes */
     210             :           );
     211             : 
     212           0 :         vec_validate_init_empty (hm->bool_ref_by_sw_if_index,
     213             :                          *sw_if_index0, ~0);
     214           0 :         hm->bool_ref_by_sw_if_index[*sw_if_index0] = 1;
     215             :       }
     216             :     else
     217             :       {
     218           0 :         hm->bool_ref_by_sw_if_index[*sw_if_index0] = ~0;
     219             :       }
     220             : 
     221             : #endif
     222             : 
     223           0 :   if (is_ipv4)
     224             :     {
     225           0 :       uword *t = NULL;
     226             :       nsh_md2_ioam_dest_tunnels_t *t1;
     227             :       fib_prefix_t key4, *key4_copy;
     228             :       hash_pair_t *hp;
     229           0 :       clib_memset (&key4, 0, sizeof (key4));
     230           0 :       key4.fp_proto = FIB_PROTOCOL_IP4;
     231           0 :       key4.fp_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32;
     232           0 :       t = hash_get_mem (hm->dst_by_ip4, &key4);
     233           0 :       if (is_add)
     234             :         {
     235           0 :           if (t)
     236             :             {
     237           0 :               return 0;
     238             :             }
     239           0 :           pool_get_aligned (hm->dst_tunnels, t1, CLIB_CACHE_LINE_BYTES);
     240           0 :           clib_memset (t1, 0, sizeof (*t1));
     241           0 :           t1->fp_proto = FIB_PROTOCOL_IP4;
     242           0 :           t1->dst_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32;
     243           0 :           key4_copy = clib_mem_alloc (sizeof (*key4_copy));
     244           0 :           clib_memset(key4_copy, 0, sizeof(*key4_copy));
     245           0 :           clib_memcpy_fast (key4_copy, &key4, sizeof (*key4_copy));
     246           0 :           hash_set_mem (hm->dst_by_ip4, key4_copy, t1 - hm->dst_tunnels);
     247             :           /*
     248             :            * Attach to the FIB entry for the VxLAN-GPE destination
     249             :            * and become its child. The dest route will invoke a callback
     250             :            * when the fib entry changes, it can be used to
     251             :            * re-program the output feature on the egress interface.
     252             :            */
     253             : 
     254           0 :           const fib_prefix_t tun_dst_pfx = {
     255             :             .fp_len = 32,
     256             :             .fp_proto = FIB_PROTOCOL_IP4,
     257           0 :             .fp_addr = {.ip4 = t1->dst_addr.ip4,}
     258             :           };
     259             : 
     260           0 :           t1->fib_entry_index =
     261           0 :             fib_table_entry_special_add (outer_fib_index,
     262             :                                          &tun_dst_pfx,
     263             :                                          FIB_SOURCE_RR,
     264             :                                          FIB_ENTRY_FLAG_NONE);
     265           0 :           t1->sibling_index =
     266           0 :             fib_entry_child_add (t1->fib_entry_index,
     267           0 :                                  hm->fib_entry_type, t1 - hm->dst_tunnels);
     268           0 :           t1->outer_fib_index = outer_fib_index;
     269             : 
     270             :         }
     271             :       else
     272             :         {
     273           0 :           if (!t)
     274             :             {
     275           0 :               return 0;
     276             :             }
     277           0 :           t1 = pool_elt_at_index (hm->dst_tunnels, t[0]);
     278           0 :           hp = hash_get_pair (hm->dst_by_ip4, &key4);
     279           0 :           key4_copy = (void *) (hp->key);
     280           0 :           hash_unset_mem (hm->dst_by_ip4, &key4);
     281           0 :           clib_mem_free (key4_copy);
     282           0 :           pool_put (hm->dst_tunnels, t1);
     283             :         }
     284             :     }
     285             :   else
     286             :     {
     287             :       // TBD for IPv6
     288             :     }
     289             : 
     290           0 :   return 0;
     291             : }
     292             : 
     293             : void
     294           0 : nsh_md2_ioam_refresh_output_feature_on_all_dest (void)
     295             : {
     296           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     297           0 :   nsh_main_t *gm = &nsh_main;
     298             :   nsh_md2_ioam_dest_tunnels_t *t;
     299             :   u32 i;
     300             : 
     301           0 :   if (pool_elts (hm->dst_tunnels) == 0)
     302           0 :     return;
     303             : 
     304           0 :   nsh_md2_ioam_clear_output_feature_on_all_intfs (gm->vlib_main);
     305           0 :   i = vec_len (hm->bool_ref_by_sw_if_index);
     306           0 :   vec_free (hm->bool_ref_by_sw_if_index);
     307           0 :   vec_validate_init_empty (hm->bool_ref_by_sw_if_index, i, ~0);
     308           0 :   pool_foreach (t, hm->dst_tunnels)
     309             :                                       {
     310           0 :                                       nsh_md2_ioam_enable_disable_for_dest
     311             :                                       (gm->vlib_main,
     312             :                                        t->dst_addr,
     313             :                                        t->outer_fib_index,
     314           0 :                                        (t->fp_proto == FIB_PROTOCOL_IP4), 1
     315             :                                        /* is_add */
     316             :                                       );
     317             :                                       }
     318           0 :   return;
     319             : }
     320             : 
     321             : void
     322           0 : nsh_md2_ioam_clear_output_feature_on_select_intfs (void)
     323             : {
     324           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     325           0 :   nsh_main_t *gm = &nsh_main;
     326             : 
     327           0 :   u32 sw_if_index0 = 0;
     328           0 :   for (sw_if_index0 = 0;
     329           0 :        sw_if_index0 < vec_len (hm->bool_ref_by_sw_if_index); sw_if_index0++)
     330             :     {
     331           0 :       if (hm->bool_ref_by_sw_if_index[sw_if_index0] == 0xFF)
     332             :         {
     333           0 :           nsh_md2_ioam_set_clear_output_feature_on_intf
     334             :             (gm->vlib_main, sw_if_index0, 0);
     335             :         }
     336             :     }
     337             : 
     338           0 :   return;
     339             : }
     340             : 
     341             : 
     342             : 
     343             : 
     344             : clib_error_t *
     345           0 : nsh_md2_ioam_enable_disable (int has_trace_option, int has_pot_option,
     346             :                                   int has_ppc_option)
     347             : {
     348           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     349             : 
     350           0 :   hm->has_trace_option = has_trace_option;
     351           0 :   hm->has_pot_option = has_pot_option;
     352           0 :   hm->has_ppc_option = has_ppc_option;
     353             : 
     354           0 :   if (hm->has_trace_option)
     355             :     {
     356           0 :       nsh_md2_ioam_trace_profile_setup ();
     357             :     }
     358           0 :   else if (!hm->has_trace_option)
     359             :     {
     360           0 :       nsh_md2_ioam_trace_profile_cleanup ();
     361             :     }
     362             : 
     363           0 :   return 0;
     364             : }
     365             : 
     366             : 
     367           0 : int nsh_md2_ioam_disable_for_dest
     368             :   (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index,
     369             :    u8 ipv4_set)
     370             : {
     371             :   nsh_md2_ioam_dest_tunnels_t *t;
     372           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     373           0 :   nsh_main_t *gm = &nsh_main;
     374             : 
     375           0 :   nsh_md2_ioam_enable_disable_for_dest (gm->vlib_main,
     376             :                                              dst_addr, outer_fib_index,
     377             :                                              ipv4_set, 0);
     378           0 :   if (pool_elts (hm->dst_tunnels) == 0)
     379             :     {
     380           0 :       nsh_md2_ioam_clear_output_feature_on_select_intfs ();
     381           0 :       return 0;
     382             :     }
     383             : 
     384           0 :   pool_foreach (t, hm->dst_tunnels)
     385             :                                       {
     386           0 :                                       nsh_md2_ioam_enable_disable_for_dest
     387             :                                       (gm->vlib_main,
     388             :                                        t->dst_addr,
     389             :                                        t->outer_fib_index,
     390           0 :                                        (t->fp_proto ==
     391             :                                         FIB_PROTOCOL_IP4), 1 /* is_add */ );
     392             :                                       }
     393           0 :   nsh_md2_ioam_clear_output_feature_on_select_intfs ();
     394           0 :   return (0);
     395             : 
     396             : }
     397             : 
     398           0 : static clib_error_t *nsh_md2_ioam_set_transit_rewrite_command_fn
     399             :   (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
     400             : {
     401           0 :   nsh_main_t *gm = &nsh_main;
     402             :   ip46_address_t dst_addr;
     403           0 :   u8 dst_addr_set = 0;
     404           0 :   u8 ipv4_set = 0;
     405           0 :   u8 ipv6_set = 0;
     406           0 :   u8 disable = 0;
     407           0 :   clib_error_t *rv = 0;
     408           0 :   u32 outer_fib_index = 0;
     409           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     410             :     {
     411           0 :       if (unformat (input, "dst-ip %U", unformat_ip4_address, &dst_addr.ip4))
     412             :         {
     413           0 :           dst_addr_set = 1;
     414           0 :           ipv4_set = 1;
     415             :         }
     416             :       else
     417           0 :         if (unformat
     418             :             (input, "dst-ip %U", unformat_ip6_address, &dst_addr.ip6))
     419             :         {
     420           0 :           dst_addr_set = 1;
     421           0 :           ipv6_set = 1;
     422             :         }
     423           0 :       else if (unformat (input, "outer-fib-index %d", &outer_fib_index))
     424             :         {
     425             :         }
     426             : 
     427           0 :       else if (unformat (input, "disable"))
     428           0 :         disable = 1;
     429             :       else
     430           0 :         break;
     431             :     }
     432             : 
     433           0 :   if (dst_addr_set == 0)
     434           0 :     return clib_error_return (0,
     435             :                               "LISP-GPE Tunnel destination address not specified");
     436           0 :   if (ipv4_set && ipv6_set)
     437           0 :     return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
     438           0 :   if (!disable)
     439             :     {
     440           0 :       nsh_md2_ioam_enable_disable_for_dest (gm->vlib_main,
     441             :                                                  dst_addr, outer_fib_index,
     442             :                                                  ipv4_set, 1);
     443             :     }
     444             :   else
     445             :     {
     446           0 :       nsh_md2_ioam_disable_for_dest
     447             :         (vm, dst_addr, outer_fib_index, ipv4_set);
     448             :     }
     449           0 :   return rv;
     450             : }
     451             : 
     452             : /* *INDENT-OFF* */
     453       58901 : VLIB_CLI_COMMAND (nsh_md2_ioam_set_transit_rewrite_cmd, static) = {
     454             :   .path = "set nsh-md2-ioam-transit",
     455             :   .short_help = "set nsh-ioam-lisp-gpe-transit dst-ip <dst_ip> [outer-fib-index <outer_fib_index>] [disable]",
     456             :   .function = nsh_md2_ioam_set_transit_rewrite_command_fn,
     457             : };
     458             : 
     459             : /**
     460             :  * Function definition to backwalk a FIB node
     461             :  */
     462             : static fib_node_back_walk_rc_t
     463           0 : nsh_md2_ioam_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
     464             : {
     465           0 :   nsh_md2_ioam_refresh_output_feature_on_all_dest ();
     466           0 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     467             : }
     468             : 
     469             : /**
     470             :  * Function definition to get a FIB node from its index
     471             :  */
     472             : static fib_node_t *
     473           0 : nsh_md2_ioam_fib_node_get (fib_node_index_t index)
     474             : {
     475           0 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     476           0 :   return (&hm->node);
     477             : }
     478             : 
     479             : /**
     480             :  * Function definition to inform the FIB node that its last lock has gone.
     481             :  */
     482             : static void
     483           0 : nsh_md2_ioam_last_lock_gone (fib_node_t * node)
     484             : {
     485           0 :   ASSERT (0);
     486           0 : }
     487             : 
     488             : 
     489             : /*
     490             :  * Virtual function table registered by MPLS GRE tunnels
     491             :  * for participation in the FIB object graph.
     492             :  */
     493             : const static fib_node_vft_t nsh_md2_ioam_vft = {
     494             :   .fnv_get = nsh_md2_ioam_fib_node_get,
     495             :   .fnv_last_lock = nsh_md2_ioam_last_lock_gone,
     496             :   .fnv_back_walk = nsh_md2_ioam_back_walk,
     497             : };
     498             : 
     499             : void
     500         575 : nsh_md2_ioam_interface_init (void)
     501             : {
     502         575 :   nsh_md2_ioam_main_t *hm = &nsh_md2_ioam_main;
     503         575 :   hm->fib_entry_type = fib_node_register_new_type ("nsh", &nsh_md2_ioam_vft);
     504         575 :   return;
     505             : }
     506             : 

Generated by: LCOV version 1.14