LCOV - code coverage report
Current view: top level - vnet/mpls - interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 44 75 58.7 %
Date: 2023-07-05 22:20:52 Functions: 8 11 72.7 %

          Line data    Source code
       1             : /*
       2             :  * interface.c: mpls interfaces
       3             :  *
       4             :  * Copyright (c) 2012 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/mpls/mpls.h>
      20             : #include <vnet/fib/mpls_fib.h>
      21             : #include <vnet/fib/ip4_fib.h>
      22             : #include <vnet/adj/adj_midchain.h>
      23             : #include <vnet/dpo/classify_dpo.h>
      24             : 
      25             : typedef struct
      26             : {
      27             :   mpls_interface_state_change_function_t *function;
      28             :   uword function_opaque;
      29             : } mpls_interface_state_change_callback_t;
      30             : 
      31             : /** Functions to call when interface becomes MPLS enabled/disabled. */
      32             : static mpls_interface_state_change_callback_t *state_change_callbacks;
      33             : 
      34             : u8
      35           0 : mpls_sw_interface_is_enabled (u32 sw_if_index)
      36             : {
      37           0 :     mpls_main_t * mm = &mpls_main;
      38             : 
      39           0 :     if (vec_len(mm->mpls_enabled_by_sw_if_index) <= sw_if_index)
      40           0 :         return (0);
      41             : 
      42           0 :     return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
      43             : }
      44             : 
      45             : void
      46           0 : mpls_interface_state_change_add_callback (
      47             :   mpls_interface_state_change_function_t *function, uword opaque)
      48             : {
      49           0 :   mpls_interface_state_change_callback_t cb = {
      50             :     .function = function,
      51             :     .function_opaque = opaque,
      52             :   };
      53           0 :   vec_add1 (state_change_callbacks, cb);
      54           0 : }
      55             : 
      56             : int
      57         276 : mpls_sw_interface_enable_disable (mpls_main_t *mm, u32 sw_if_index,
      58             :                                   u8 is_enable)
      59             : {
      60             :   fib_node_index_t lfib_index;
      61         276 :   vnet_main_t *vnm = vnet_get_main ();
      62         276 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
      63             : 
      64         276 :   vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
      65             : 
      66         276 :   lfib_index = fib_table_find(FIB_PROTOCOL_MPLS,
      67             :                               MPLS_FIB_DEFAULT_TABLE_ID);
      68             : 
      69         276 :   if (~0 == lfib_index)
      70           0 :        return VNET_API_ERROR_NO_SUCH_FIB;
      71             : 
      72             :   /*
      73             :    * enable/disable only on the 1<->0 transition
      74             :    */
      75         276 :   if (is_enable)
      76             :     {
      77         138 :       if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
      78           0 :           return (0);
      79             : 
      80         138 :       fib_table_lock (lfib_index, FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
      81             : 
      82         138 :       vec_validate(mm->fib_index_by_sw_if_index, sw_if_index);
      83         138 :       mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
      84             :     }
      85             :   else
      86             :     {
      87         138 :       ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
      88         138 :       if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
      89           0 :           return (0);
      90             : 
      91         138 :       fib_table_unlock (mm->fib_index_by_sw_if_index[sw_if_index],
      92             :                         FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
      93             :     }
      94             : 
      95         276 :   vnet_feature_enable_disable ("mpls-input", "mpls-not-enabled",
      96             :                                sw_if_index, !is_enable, 0, 0);
      97             : 
      98         276 :   if (is_enable)
      99         138 :     hi->l3_if_count++;
     100         138 :   else if (hi->l3_if_count)
     101         138 :     hi->l3_if_count--;
     102             : 
     103             :   {
     104             :     mpls_interface_state_change_callback_t *cb;
     105         276 :     vec_foreach (cb, state_change_callbacks)
     106           0 :       cb->function (mm, cb->function_opaque, sw_if_index, is_enable);
     107             :   }
     108             : 
     109         276 :   return (0);
     110             : }
     111             : 
     112             : static clib_error_t *
     113           0 : mpls_interface_enable_disable (vlib_main_t * vm,
     114             :                                unformat_input_t * input,
     115             :                                vlib_cli_command_t * cmd)
     116             : {
     117           0 :   vnet_main_t * vnm = vnet_get_main();
     118           0 :   clib_error_t * error = 0;
     119             :   u32 sw_if_index, enable;
     120             :   int rv;
     121             : 
     122           0 :   sw_if_index = ~0;
     123             : 
     124           0 :   if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     125             :     {
     126           0 :       error = clib_error_return (0, "unknown interface `%U'",
     127             :                                  format_unformat_error, input);
     128           0 :       goto done;
     129             :     }
     130             : 
     131           0 :   if (unformat (input, "enable"))
     132           0 :       enable = 1;
     133           0 :   else if (unformat (input, "disable"))
     134           0 :       enable = 0;
     135             :   else
     136             :     {
     137           0 :       error = clib_error_return (0, "expected 'enable' or 'disable'",
     138             :                                  format_unformat_error, input);
     139           0 :       goto done;
     140             :     }
     141             : 
     142           0 :   rv = mpls_sw_interface_enable_disable (&mpls_main, sw_if_index, enable);
     143             : 
     144           0 :   if (VNET_API_ERROR_NO_SUCH_FIB == rv)
     145           0 :       error = clib_error_return (0, "default MPLS table must be created first");
     146             : 
     147           0 :  done:
     148           0 :   return error;
     149             : }
     150             : 
     151             : /*?
     152             :  * This command enables an interface to accept MPLS packets
     153             :  *
     154             :  * @cliexpar
     155             :  * @cliexstart{set interface mpls}
     156             :  *  set interface mpls GigEthernet0/8/0 enable
     157             :  * @cliexend
     158             :  ?*/
     159      272887 : VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
     160             :   .path = "set interface mpls",
     161             :   .function = mpls_interface_enable_disable,
     162             :   .short_help = "Enable/Disable an interface for MPLS forwarding",
     163             : };
     164             : 
     165             : static void
     166           9 : show_mpls_one_interface (vnet_main_t *vnm, vlib_main_t *vm, u32 sw_if_index,
     167             :                          bool verbose)
     168             : {
     169           9 :   mpls_main_t *mm = &mpls_main;
     170             :   u8 enabled;
     171             : 
     172           9 :   enabled = mm->mpls_enabled_by_sw_if_index[sw_if_index];
     173             : 
     174           9 :   if (enabled)
     175             :     {
     176           5 :       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
     177             :                        sw_if_index);
     178           5 :       vlib_cli_output (vm, "  MPLS enabled");
     179             :     }
     180           4 :   else if (verbose)
     181             :     {
     182           1 :       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
     183             :                        sw_if_index);
     184           1 :       vlib_cli_output (vm, "  MPLS disabled");
     185             :     }
     186           9 : }
     187             : 
     188             : static walk_rc_t
     189           6 : show_mpls_interface_walk (vnet_main_t *vnm, vnet_sw_interface_t *si, void *ctx)
     190             : {
     191           6 :   show_mpls_one_interface (vnm, ctx, si->sw_if_index, false);
     192             : 
     193           6 :   return (WALK_CONTINUE);
     194             : }
     195             : 
     196             : static clib_error_t *
     197           5 : show_mpls_interface (vlib_main_t *vm, unformat_input_t *input,
     198             :                      vlib_cli_command_t *cmd)
     199             : {
     200           5 :   vnet_main_t *vnm = vnet_get_main ();
     201             :   u32 sw_if_index;
     202             : 
     203           5 :   sw_if_index = ~0;
     204             : 
     205           5 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     206             :     ;
     207             : 
     208           5 :   if (~0 == sw_if_index)
     209             :     {
     210           2 :       vnet_sw_interface_walk (vnm, show_mpls_interface_walk, vm);
     211             :     }
     212             :   else
     213             :     {
     214           3 :       show_mpls_one_interface (vnm, vm, sw_if_index, true);
     215             :     }
     216             : 
     217           5 :   return NULL;
     218             : }
     219             : 
     220             : /*?
     221             :  * This command displays the MPLS forwarding state of an interface
     222             :  *
     223             :  * @cliexpar
     224             :  * @cliexstart{show mpls interface}
     225             :  *  set mpls interface GigEthernet0/8/0
     226             :  * @cliexend
     227             :  ?*/
     228      272887 : VLIB_CLI_COMMAND (show_mpls_interface_command, static) = {
     229             :   .path = "show mpls interface",
     230             :   .function = show_mpls_interface,
     231             :   .short_help = "Show MPLS interface forwarding",
     232             : };

Generated by: LCOV version 1.14