LCOV - code coverage report
Current view: top level - vnet/mpls - mpls.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 30 196 15.3 %
Date: 2023-10-26 01:39:38 Functions: 12 20 60.0 %

          Line data    Source code
       1             : /*
       2             :  * mpls.c: mpls
       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/ip4_fib.h>
      21             : #include <vnet/fib/mpls_fib.h>
      22             : 
      23             : const static char* mpls_eos_bit_names[] = MPLS_EOS_BITS;
      24             : 
      25             : mpls_main_t mpls_main;
      26             : 
      27       13097 : u8 * format_mpls_unicast_label (u8 * s, va_list * args)
      28             : {
      29       13097 :   mpls_label_t label = va_arg (*args, mpls_label_t);
      30             : 
      31       13097 :   switch (label) {
      32           0 :   case MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL:
      33           0 :       s = format (s, "%s", MPLS_IETF_IPV4_EXPLICIT_NULL_STRING);
      34           0 :       break;
      35           0 :   case MPLS_IETF_ROUTER_ALERT_LABEL:
      36           0 :       s = format (s, "%s", MPLS_IETF_ROUTER_ALERT_STRING);
      37           0 :       break;
      38           0 :   case MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL:
      39           0 :       s = format (s, "%s", MPLS_IETF_IPV6_EXPLICIT_NULL_STRING);
      40           0 :       break;
      41           0 :   case MPLS_IETF_IMPLICIT_NULL_LABEL:
      42           0 :       s = format (s, "%s", MPLS_IETF_IMPLICIT_NULL_STRING);
      43           0 :       break;
      44           0 :   case MPLS_IETF_ELI_LABEL:
      45           0 :       s = format (s, "%s", MPLS_IETF_ELI_STRING);
      46           0 :       break;
      47           0 :   case MPLS_IETF_GAL_LABEL:
      48           0 :       s = format (s, "%s", MPLS_IETF_GAL_STRING);
      49           0 :       break;
      50           0 :   case MPLS_LABEL_POP:
      51           0 :       s = format (s, "pop");
      52           0 :       break;
      53       13097 :   default:
      54       13097 :       s = format (s, "%d", label);
      55       13097 :       break;
      56             :   }
      57       13097 :   return s;
      58             : }
      59             : 
      60           0 : uword unformat_mpls_unicast_label (unformat_input_t * input, va_list * args)
      61             : {
      62           0 :   mpls_label_t *label = va_arg (*args, mpls_label_t*);
      63             :   
      64           0 :   if (unformat (input, MPLS_IETF_IPV4_EXPLICIT_NULL_STRING))
      65           0 :       *label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
      66           0 :   else if (unformat (input, MPLS_IETF_IPV6_EXPLICIT_NULL_STRING))
      67           0 :       *label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
      68           0 :   else if (unformat (input, MPLS_IETF_ROUTER_ALERT_STRING))
      69           0 :       *label = MPLS_IETF_ROUTER_ALERT_LABEL;
      70           0 :   else if (unformat (input, MPLS_IETF_IMPLICIT_NULL_STRING))
      71           0 :       *label = MPLS_IETF_IMPLICIT_NULL_LABEL;
      72           0 :   else if (unformat (input, MPLS_IETF_IPV4_EXPLICIT_NULL_BRIEF_STRING))
      73           0 :       *label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
      74           0 :   else if (unformat (input, MPLS_IETF_IPV6_EXPLICIT_NULL_BRIEF_STRING))
      75           0 :       *label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
      76           0 :   else if (unformat (input, MPLS_IETF_ROUTER_ALERT_BRIEF_STRING))
      77           0 :       *label = MPLS_IETF_ROUTER_ALERT_LABEL;
      78           0 :   else if (unformat (input, MPLS_IETF_IMPLICIT_NULL_BRIEF_STRING))
      79           0 :       *label = MPLS_IETF_IMPLICIT_NULL_LABEL;
      80           0 :   else if (unformat (input, "%d", label))
      81             :       ;
      82             :   else
      83           0 :     return (0);
      84             : 
      85           0 :   return (1);
      86             : }
      87             : 
      88       13093 : u8 * format_mpls_eos_bit (u8 * s, va_list * args)
      89             : {
      90       13093 :   mpls_eos_bit_t eb = va_arg (*args, mpls_eos_bit_t);
      91             : 
      92       13093 :   ASSERT(eb <= MPLS_EOS);
      93             : 
      94       13093 :   s = format(s, "%s", mpls_eos_bit_names[eb]);
      95             : 
      96       13093 :   return (s);
      97             : }
      98             : 
      99       13089 : u8 * format_mpls_header (u8 * s, va_list * args)
     100             : {
     101       13089 :   mpls_unicast_header_t hdr = va_arg (*args, mpls_unicast_header_t);
     102             : 
     103       13089 :   return (format(s, "[%U:%d:%d:%U]",
     104             :                  format_mpls_unicast_label, 
     105             :                  vnet_mpls_uc_get_label(hdr.label_exp_s_ttl),
     106             :                  vnet_mpls_uc_get_ttl(hdr.label_exp_s_ttl),
     107             :                  vnet_mpls_uc_get_exp(hdr.label_exp_s_ttl),
     108             :                  format_mpls_eos_bit,
     109             :                  vnet_mpls_uc_get_s(hdr.label_exp_s_ttl)));
     110             : }
     111             : 
     112             : uword
     113           0 : unformat_mpls_header (unformat_input_t * input, va_list * args)
     114             : {
     115           0 :   u8 ** result = va_arg (*args, u8 **);
     116           0 :   mpls_unicast_header_t _h, * h = &_h;
     117             :   u32 label, label_exp_s_ttl;
     118             : 
     119           0 :   if (! unformat (input, "MPLS %d", &label))
     120           0 :     return 0;
     121             : 
     122           0 :   label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF;
     123           0 :   h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl);
     124             : 
     125             :   /* Add gre, mpls headers to result. */
     126             :   {
     127             :     void * p;
     128           0 :     u32 h_n_bytes = sizeof (h[0]);
     129             : 
     130           0 :     vec_add2 (*result, p, h_n_bytes);
     131           0 :     clib_memcpy (p, h, h_n_bytes);
     132             :   }
     133             : 
     134           0 :   return 1;
     135             : }
     136             : 
     137             : uword
     138           0 : unformat_mpls_label_net_byte_order (unformat_input_t * input,
     139             :                                         va_list * args)
     140             : {
     141           0 :   u32 * result = va_arg (*args, u32 *);
     142             :   u32 label;
     143             : 
     144           0 :   if (!unformat (input, "MPLS: label %d", &label))
     145           0 :     return 0;
     146             : 
     147           0 :   label = (label<<12) | (1<<8) /* s-bit set */ | 0xFF /* ttl */;
     148             : 
     149           0 :   *result = clib_host_to_net_u32 (label);
     150           0 :   return 1;
     151             : }
     152             : 
     153       10740 : u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
     154             : {
     155       10740 :   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
     156       10740 :   u32 label = h->label_exp_s_ttl;
     157             :   
     158       10740 :   s = format (s, "label %d exp %d, s %d, ttl %d",
     159             :               vnet_mpls_uc_get_label (label),
     160             :               vnet_mpls_uc_get_exp (label),
     161             :               vnet_mpls_uc_get_s (label),
     162             :               vnet_mpls_uc_get_ttl (label));
     163       10740 :   return s;
     164             : }
     165             : 
     166       10740 : u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
     167             : {
     168       10740 :   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
     169             :   mpls_unicast_header_t h_host;
     170             : 
     171       10740 :   h_host.label_exp_s_ttl = clib_net_to_host_u32 (h->label_exp_s_ttl);
     172             : 
     173       10740 :   return format (s, "%U", format_mpls_unicast_header_host_byte_order,
     174             :                  &h_host);
     175             : }
     176             : 
     177             : typedef struct {
     178             :   u32 fib_index;
     179             :   u32 entry_index;
     180             :   u32 dest;
     181             :   u32 s_bit;
     182             :   u32 label;
     183             : } show_mpls_fib_t;
     184             : 
     185             : int
     186           0 : mpls_dest_cmp(void * a1, void * a2)
     187             : {
     188           0 :   show_mpls_fib_t * r1 = a1;
     189           0 :   show_mpls_fib_t * r2 = a2;
     190             : 
     191           0 :   return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
     192             : }
     193             : 
     194             : int
     195           0 : mpls_fib_index_cmp(void * a1, void * a2)
     196             : {
     197           0 :   show_mpls_fib_t * r1 = a1;
     198           0 :   show_mpls_fib_t * r2 = a2;
     199             : 
     200           0 :   return r1->fib_index - r2->fib_index;
     201             : }
     202             : 
     203             : int
     204           0 : mpls_label_cmp(void * a1, void * a2)
     205             : {
     206           0 :   show_mpls_fib_t * r1 = a1;
     207           0 :   show_mpls_fib_t * r2 = a2;
     208             : 
     209           0 :   return r1->label - r2->label;
     210             : }
     211             : 
     212             : static clib_error_t *
     213           0 : vnet_mpls_local_label (vlib_main_t * vm,
     214             :                        unformat_input_t * input,
     215             :                        vlib_cli_command_t * cmd)
     216             : {
     217           0 :   unformat_input_t _line_input, * line_input = &_line_input;
     218             :   u32 table_id, is_del, is_ip, payload_proto;
     219           0 :   fib_route_path_t *rpaths = NULL, rpath;
     220             :   mpls_label_t local_label;
     221             :   clib_error_t * error;
     222             :   mpls_eos_bit_t eos;
     223             :   fib_prefix_t pfx;
     224             : 
     225           0 :   error = NULL;
     226           0 :   is_ip = 0;
     227           0 :   table_id = 0;
     228           0 :   eos = MPLS_EOS;
     229           0 :   is_del = 0;
     230           0 :   local_label = MPLS_LABEL_INVALID;
     231           0 :   clib_memset(&pfx, 0, sizeof(pfx));
     232           0 :   payload_proto = DPO_PROTO_MPLS;
     233             : 
     234             :    /* Get a line of input. */
     235           0 :   if (! unformat_user (input, unformat_line_input, line_input))
     236           0 :     return 0;
     237             : 
     238           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     239             :     {
     240           0 :       if (unformat (line_input, "table %d", &table_id))
     241             :         ;
     242           0 :       else if (unformat (line_input, "del"))
     243           0 :         is_del = 1;
     244           0 :       else if (unformat (line_input, "add"))
     245           0 :         is_del = 0;
     246           0 :       else if (unformat (line_input, "eos"))
     247           0 :         pfx.fp_eos = MPLS_EOS;
     248           0 :       else if (unformat (line_input, "non-eos"))
     249           0 :         pfx.fp_eos = MPLS_NON_EOS;
     250           0 :       else if (unformat (line_input, "%U/%d",
     251             :                          unformat_ip4_address,
     252             :                          &pfx.fp_addr.ip4,
     253             :                          &pfx.fp_len))
     254             :       {
     255           0 :           pfx.fp_proto = FIB_PROTOCOL_IP4;
     256           0 :           is_ip = 1;
     257             :       }
     258           0 :       else if (unformat (line_input, "%U/%d",
     259             :                          unformat_ip6_address,
     260             :                          &pfx.fp_addr.ip6,
     261             :                          &pfx.fp_len))
     262             :       {
     263           0 :           pfx.fp_proto = FIB_PROTOCOL_IP6;
     264           0 :           is_ip = 1;
     265             :       }
     266           0 :       else if (unformat (line_input, "via %U",
     267             :                          unformat_fib_route_path,
     268             :                          &rpath, &payload_proto))
     269             :       {
     270           0 :           pfx.fp_payload_proto = payload_proto;
     271           0 :           vec_add1(rpaths, rpath);
     272             :       }
     273           0 :       else if (unformat (line_input, "%d", &local_label))
     274             :         ;
     275             :       else
     276             :       {
     277           0 :           error = clib_error_return (0, "unknown input: %U",
     278             :                                      format_unformat_error, line_input);
     279           0 :           goto done;
     280             :       }
     281             : 
     282             :     }
     283             : 
     284           0 :   if (MPLS_LABEL_INVALID == local_label)
     285             :   {
     286           0 :       error = clib_error_return (0, "local-label required: %U",
     287             :                                  format_unformat_error, input);
     288           0 :       goto done;
     289             :   }
     290             : 
     291             : 
     292           0 :   if (is_ip)
     293             :   {
     294           0 :       u32 fib_index = fib_table_find(pfx.fp_proto, table_id);
     295             : 
     296           0 :       if (FIB_NODE_INDEX_INVALID == fib_index)
     297             :       {
     298           0 :           error = clib_error_return (0, "%U table-id %d does not exist",
     299             :                                      format_fib_protocol, pfx.fp_proto, table_id);
     300           0 :           goto done;
     301             :       }
     302             : 
     303           0 :       if (is_del)
     304             :       {
     305           0 :           fib_table_entry_local_label_remove(fib_index, &pfx, local_label);
     306             :       }
     307             :       else
     308             :       {
     309           0 :           fib_table_entry_local_label_add(fib_index, &pfx, local_label);
     310             :       }
     311             :   }
     312             :   else
     313             :   {
     314             :       fib_node_index_t fib_index;
     315             : 
     316           0 :       if (NULL == rpaths)
     317             :       {
     318           0 :           error = clib_error_return(0 , "no paths");
     319           0 :           goto done;
     320             :       }
     321             : 
     322           0 :       pfx.fp_proto = FIB_PROTOCOL_MPLS;
     323           0 :       pfx.fp_len = 21;
     324           0 :       pfx.fp_label = local_label;
     325           0 :       pfx.fp_payload_proto = rpaths[0].frp_proto;
     326             : 
     327           0 :       fib_index = mpls_fib_index_from_table_id(table_id);
     328             : 
     329           0 :       if (FIB_NODE_INDEX_INVALID == fib_index)
     330             :       {
     331           0 :           error = clib_error_return (0, "MPLS table-id %d does not exist",
     332             :                                      table_id);
     333           0 :           goto done;
     334             :       }
     335             : 
     336           0 :       if (is_del)
     337             :       {
     338           0 :           fib_table_entry_path_remove2(fib_index,
     339             :                                        &pfx,
     340             :                                        FIB_SOURCE_CLI,
     341             :                                        rpaths);
     342             :       }
     343             :       else
     344             :       {
     345             :           fib_node_index_t lfe;
     346             : 
     347           0 :           lfe = fib_table_entry_path_add2(fib_index,
     348             :                                           &pfx,
     349             :                                           FIB_SOURCE_CLI,
     350             :                                           FIB_ENTRY_FLAG_NONE,
     351             :                                           rpaths);
     352             : 
     353           0 :           if (FIB_NODE_INDEX_INVALID == lfe)
     354             :           {
     355           0 :               error = clib_error_return (0, "Failed to create %U-%U in MPLS table-id %d",
     356             :                                          format_mpls_unicast_label, local_label,
     357             :                                          format_mpls_eos_bit, eos,
     358             :                                          table_id);
     359           0 :               goto done;
     360             :           }
     361             :       }
     362             :   }
     363             : 
     364           0 : done:
     365           0 :   unformat_free (line_input);
     366             : 
     367           0 :   return error;
     368             : }
     369             : 
     370      285289 : VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
     371             :   .path = "mpls local-label",
     372             :   .function = vnet_mpls_local_label,
     373             :   .short_help = "mpls local-label [add|del] <label-value> [eos|non-eos] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-attached] [rx-ip4 <interface>] [out-labels <value value value>]",
     374             : };
     375             : 
     376             : clib_error_t *
     377           0 : vnet_mpls_table_cmd (vlib_main_t * vm,
     378             :                      unformat_input_t * main_input,
     379             :                      vlib_cli_command_t * cmdo)
     380             : {
     381           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     382           0 :   clib_error_t *error = NULL;
     383             :   u32 table_id, is_add;
     384           0 :   u8 *name = NULL;
     385             : 
     386           0 :   is_add = 1;
     387           0 :   table_id = ~0;
     388             : 
     389             :   /* Get a line of input. */
     390           0 :   if (!unformat_user (main_input, unformat_line_input, line_input))
     391           0 :     return 0;
     392             : 
     393           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     394             :     {
     395           0 :       if (unformat (line_input, "%d", &table_id))
     396             :         ;
     397           0 :       else if (unformat (line_input, "del"))
     398           0 :         is_add = 0;
     399           0 :       else if (unformat (line_input, "add"))
     400           0 :         is_add = 1;
     401           0 :       else if (unformat (line_input, "name %s", &name))
     402             :         ;
     403             :       else
     404             :         {
     405           0 :           error = unformat_parse_error (line_input);
     406           0 :           goto done;
     407             :         }
     408             :     }
     409             : 
     410           0 :   if (~0 == table_id)
     411             :     {
     412           0 :       error = clib_error_return (0, "No table id");
     413           0 :       goto done;
     414             :     }
     415             :   else
     416             :     {
     417           0 :       if (is_add)
     418             :         {
     419           0 :             mpls_table_create (table_id, 0, name);
     420             :         }
     421             :       else
     422             :         {
     423           0 :           mpls_table_delete (table_id, 0);
     424             :         }
     425             :     }
     426             : 
     427           0 :  done:
     428           0 :    vec_free (name);
     429           0 :    unformat_free (line_input);
     430           0 :    return error;
     431             : }
     432             : 
     433             : /* *INDENT-ON* */
     434             : /*?
     435             :  * This command is used to add or delete MPLS Tables. All
     436             :  * Tables must be explicitly added before that can be used,
     437             :  * Including the default table.
     438             :  ?*/
     439             : /* *INDENT-OFF* */
     440      285289 : VLIB_CLI_COMMAND (mpls_table_command, static) = {
     441             :   .path = "mpls table",
     442             :   .short_help = "mpls table [add|del] <table-id>",
     443             :   .function = vnet_mpls_table_cmd,
     444             :   .is_mp_safe = 1,
     445             : };
     446             : 
     447             : static clib_error_t *
     448         575 : mpls_init (vlib_main_t * vm)
     449             : {
     450             :   clib_error_t * error;
     451             : 
     452         575 :   if ((error = vlib_call_init_function (vm, ip_main_init)))
     453           0 :     return error;
     454             : 
     455         575 :   return vlib_call_init_function (vm, mpls_input_init);
     456             : }
     457             : 
     458       14399 : VLIB_INIT_FUNCTION (mpls_init);

Generated by: LCOV version 1.14