LCOV - code coverage report
Current view: top level - vnet/ip - lookup.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 162 358 45.3 %
Date: 2023-10-26 01:39:38 Functions: 39 44 88.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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             :  * ip/ip_lookup.c: ip4/6 adjacency and lookup table management
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vnet/ip/ip.h>
      41             : #include <vnet/adj/adj.h>
      42             : #include <vnet/fib/fib_table.h>
      43             : #include <vnet/fib/ip4_fib.h>
      44             : #include <vnet/fib/ip6_fib.h>
      45             : #include <vnet/mpls/mpls.h>
      46             : #include <vnet/mfib/mfib_table.h>
      47             : #include <vnet/dpo/drop_dpo.h>
      48             : #include <vnet/dpo/classify_dpo.h>
      49             : #include <vnet/dpo/punt_dpo.h>
      50             : #include <vnet/dpo/receive_dpo.h>
      51             : #include <vnet/dpo/ip_null_dpo.h>
      52             : 
      53             : /**
      54             :  * @file
      55             :  * @brief IPv4 and IPv6 adjacency and lookup table management.
      56             :  *
      57             :  */
      58             : 
      59             : static clib_error_t *
      60       11798 : ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
      61             : {
      62       15752 :   vec_validate_init_empty (ip4_main.
      63             :                            lookup_main.if_address_pool_index_by_sw_if_index,
      64             :                            sw_if_index, ~0);
      65       15752 :   vec_validate_init_empty (ip6_main.
      66             :                            lookup_main.if_address_pool_index_by_sw_if_index,
      67             :                            sw_if_index, ~0);
      68             : 
      69       11798 :   return (NULL);
      70             : }
      71             : 
      72        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
      73             : 
      74             : void
      75        1150 : ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
      76             : {
      77        1150 :   if (!lm->fib_result_n_bytes)
      78        1150 :     lm->fib_result_n_bytes = sizeof (uword);
      79             : 
      80        1150 :   lm->is_ip6 = is_ip6;
      81        1150 :   mhash_init (&lm->prefix_to_if_prefix_index, sizeof (uword),
      82             :               sizeof (ip_interface_prefix_key_t));
      83        1150 :   if (is_ip6)
      84             :     {
      85         575 :       lm->format_address_and_length = format_ip6_address_and_length;
      86         575 :       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
      87             :                   sizeof (ip6_address_fib_t));
      88             :     }
      89             :   else
      90             :     {
      91         575 :       lm->format_address_and_length = format_ip4_address_and_length;
      92         575 :       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
      93             :                   sizeof (ip4_address_fib_t));
      94             :     }
      95             : 
      96             :   {
      97             :     int i;
      98             : 
      99             :     /* Setup all IP protocols to be punted and builtin-unknown. */
     100      295550 :     for (i = 0; i < 256; i++)
     101             :       {
     102      294400 :         lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
     103      294400 :         lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
     104             :       }
     105             : 
     106        1150 :     lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
     107        1150 :     lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
     108        1150 :                                   IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
     109        1150 :     lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
     110             :       IP_BUILTIN_PROTOCOL_UDP;
     111        1150 :     lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
     112        1150 :                                         IP_PROTOCOL_ICMP] =
     113             :       IP_BUILTIN_PROTOCOL_ICMP;
     114             :   }
     115        1150 : }
     116             : 
     117             : u8 *
     118         572 : format_ip_flow_hash_config (u8 * s, va_list * args)
     119             : {
     120         572 :   flow_hash_config_t flow_hash_config = va_arg (*args, u32);
     121             : 
     122             : #define _(n, b, v)                                                            \
     123             :   if (flow_hash_config & v)                                                   \
     124             :     s = format (s, "%s ", #n);
     125         572 :   foreach_flow_hash_bit;
     126             : #undef _
     127             : 
     128         572 :   return s;
     129             : }
     130             : 
     131             : uword
     132           0 : unformat_ip_flow_hash_config (unformat_input_t *input, va_list *args)
     133             : {
     134           0 :   flow_hash_config_t *flow_hash_config = va_arg (*args, flow_hash_config_t *);
     135           0 :   uword start_index = unformat_check_input (input);
     136           0 :   int matched_once = 0;
     137             : 
     138           0 :   if (unformat (input, "default"))
     139             :     {
     140           0 :       *flow_hash_config = IP_FLOW_HASH_DEFAULT;
     141           0 :       return 1;
     142             :     }
     143           0 :   while (!unformat_is_eof (input) &&
     144           0 :          !is_white_space (unformat_peek_input (input)))
     145             :     {
     146           0 :       if (unformat (input, "%_,"))
     147             :         ;
     148             : #define _(a, b, c)                                                            \
     149             :   else if (unformat (input, "%_" #a))                                         \
     150             :   {                                                                           \
     151             :     *flow_hash_config |= c;                                                   \
     152             :     matched_once = 1;                                                         \
     153             :   }
     154           0 :       foreach_flow_hash_bit
     155             : #undef _
     156             :         else
     157             :       {
     158             :         /* Roll back to our start */
     159           0 :         input->index = start_index;
     160           0 :         return 0;
     161             :       }
     162             :     }
     163             : 
     164           0 :   return matched_once;
     165             : }
     166             : 
     167             : u8 *
     168      335953 : format_ip_adjacency_packet_data (u8 * s, va_list * args)
     169             : {
     170      335953 :   u8 *packet_data = va_arg (*args, u8 *);
     171      335953 :   u32 n_packet_data_bytes = va_arg (*args, u32);
     172             : 
     173      335953 :   s = format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
     174             : 
     175      335953 :   return s;
     176             : }
     177             : 
     178             : static uword
     179           2 : unformat_dpo (unformat_input_t * input, va_list * args)
     180             : {
     181           2 :   dpo_id_t *dpo = va_arg (*args, dpo_id_t *);
     182           2 :   fib_protocol_t fp = va_arg (*args, int);
     183             :   dpo_proto_t proto;
     184             : 
     185           2 :   proto = fib_proto_to_dpo (fp);
     186             : 
     187           2 :   if (unformat (input, "drop"))
     188           2 :     dpo_copy (dpo, drop_dpo_get (proto));
     189           0 :   else if (unformat (input, "punt"))
     190           0 :     dpo_copy (dpo, punt_dpo_get (proto));
     191           0 :   else if (unformat (input, "local"))
     192           0 :     receive_dpo_add_or_lock (proto, ~0, NULL, dpo);
     193           0 :   else if (unformat (input, "null-send-unreach"))
     194           0 :     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
     195           0 :   else if (unformat (input, "null-send-prohibit"))
     196           0 :     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
     197           0 :   else if (unformat (input, "null"))
     198           0 :     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_NONE, dpo);
     199           0 :   else if (unformat (input, "classify"))
     200             :     {
     201             :       u32 classify_table_index;
     202             : 
     203           0 :       if (!unformat (input, "%d", &classify_table_index))
     204             :         {
     205           0 :           clib_warning ("classify adj must specify table index");
     206           0 :           return 0;
     207             :         }
     208             : 
     209           0 :       dpo_set (dpo, DPO_CLASSIFY, proto,
     210             :                classify_dpo_create (proto, classify_table_index));
     211             :     }
     212             :   else
     213           0 :     return 0;
     214             : 
     215           2 :   return 1;
     216             : }
     217             : 
     218             : const ip46_address_t zero_addr = {
     219             :   .as_u64 = {
     220             :              0, 0},
     221             : };
     222             : 
     223             : bool
     224        7453 : fib_prefix_validate (const fib_prefix_t *prefix)
     225             : {
     226        7453 :   if (FIB_PROTOCOL_IP4 == prefix->fp_proto)
     227             :     {
     228        4469 :       if (prefix->fp_len > 32)
     229             :         {
     230           0 :           return false;
     231             :         }
     232             :     }
     233             : 
     234        7453 :   if (FIB_PROTOCOL_IP6 == prefix->fp_proto)
     235             :     {
     236        2918 :       if (prefix->fp_len > 128)
     237             :         {
     238           0 :           return false;
     239             :         }
     240             :     }
     241        7453 :   return true;
     242             : }
     243             : 
     244             : static clib_error_t *
     245          19 : vnet_ip_route_cmd (vlib_main_t * vm,
     246             :                    unformat_input_t * main_input, vlib_cli_command_t * cmd)
     247             : {
     248          19 :   unformat_input_t _line_input, *line_input = &_line_input;
     249             :   u32 table_id, is_del, fib_index, payload_proto;
     250          19 :   dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
     251          19 :   fib_route_path_t *rpaths = NULL, rpath;
     252          19 :   fib_prefix_t *prefixs = NULL, pfx;
     253          19 :   clib_error_t *error = NULL;
     254             :   f64 count;
     255             :   int i;
     256             : 
     257          19 :   is_del = 0;
     258          19 :   table_id = 0;
     259          19 :   count = 1;
     260          19 :   clib_memset (&pfx, 0, sizeof (pfx));
     261             : 
     262             :   /* Get a line of input. */
     263          19 :   if (!unformat_user (main_input, unformat_line_input, line_input))
     264           0 :     return 0;
     265             : 
     266          78 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     267             :     {
     268          59 :       clib_memset (&rpath, 0, sizeof (rpath));
     269             : 
     270          59 :       if (unformat (line_input, "table %d", &table_id))
     271             :         ;
     272          57 :       else if (unformat (line_input, "count %f", &count))
     273             :         ;
     274             : 
     275          57 :       else if (unformat (line_input, "%U/%d",
     276             :                          unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
     277             :         {
     278           2 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
     279           2 :           vec_add1 (prefixs, pfx);
     280             :         }
     281          55 :       else if (unformat (line_input, "%U/%d",
     282             :                          unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
     283             :         {
     284          17 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
     285          17 :           vec_add1 (prefixs, pfx);
     286             :         }
     287          38 :       else if (unformat (line_input, "via %U",
     288             :                          unformat_fib_route_path, &rpath, &payload_proto))
     289             :         {
     290          17 :           vec_add1 (rpaths, rpath);
     291             :         }
     292          23 :       else if (vec_len (prefixs) > 0 &&
     293           2 :                unformat (line_input, "via %U",
     294           2 :                          unformat_dpo, &dpo, prefixs[0].fp_proto))
     295             :         {
     296           2 :           vec_add1 (dpos, dpo);
     297             :         }
     298          19 :       else if (unformat (line_input, "del"))
     299           0 :         is_del = 1;
     300          19 :       else if (unformat (line_input, "add"))
     301          19 :         is_del = 0;
     302             :       else
     303             :         {
     304           0 :           error = unformat_parse_error (line_input);
     305           0 :           goto done;
     306             :         }
     307             :     }
     308             : 
     309          19 :   if (vec_len (prefixs) == 0)
     310             :     {
     311             :       error =
     312           0 :         clib_error_return (0, "expected ip4/ip6 destination address/length.");
     313           0 :       goto done;
     314             :     }
     315             : 
     316          19 :   if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
     317             :     {
     318           0 :       error = clib_error_return (0, "expected paths.");
     319           0 :       goto done;
     320             :     }
     321             : 
     322          19 :   if (~0 == table_id)
     323             :     {
     324             :       /*
     325             :        * if no table_id is passed we will manipulate the default
     326             :        */
     327           0 :       fib_index = 0;
     328             :     }
     329             :   else
     330             :     {
     331          19 :       fib_index = fib_table_find (prefixs[0].fp_proto, table_id);
     332             : 
     333          19 :       if (~0 == fib_index)
     334             :         {
     335           0 :           error = clib_error_return (0, "Nonexistent table id %d", table_id);
     336           0 :           goto done;
     337             :         }
     338             :     }
     339             : 
     340          38 :   for (i = 0; i < vec_len (prefixs); i++)
     341             :     {
     342          19 :       if (is_del && 0 == vec_len (rpaths))
     343             :         {
     344           0 :           fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
     345             :         }
     346          19 :       else if (!is_del && 1 == vec_len (dpos))
     347             :         {
     348           2 :           fib_table_entry_special_dpo_add (fib_index,
     349           2 :                                            &prefixs[i],
     350             :                                            FIB_SOURCE_CLI,
     351             :                                            FIB_ENTRY_FLAG_EXCLUSIVE,
     352             :                                            &dpos[0]);
     353           2 :           dpo_reset (&dpos[0]);
     354             :         }
     355          17 :       else if (vec_len (dpos) > 0)
     356             :         {
     357             :           error =
     358           0 :             clib_error_return (0,
     359             :                                "Load-balancing over multiple special adjacencies is unsupported");
     360           0 :           goto done;
     361             :         }
     362          17 :       else if (0 < vec_len (rpaths))
     363          17 :         {
     364             :           u32 k, n;
     365             :           f64 t[2];
     366          17 :           n = count;
     367          17 :           t[0] = vlib_time_now (vm);
     368             : 
     369          34 :           for (k = 0; k < n; k++)
     370             :             {
     371          17 :               fib_prefix_t rpfx = {
     372          17 :                 .fp_len = prefixs[i].fp_len,
     373          17 :                 .fp_proto = prefixs[i].fp_proto,
     374          17 :                 .fp_addr = prefixs[i].fp_addr,
     375             :               };
     376             : 
     377          17 :               if (!fib_prefix_validate (&rpfx))
     378             :                 {
     379           0 :                   vlib_cli_output (vm, "Invalid prefix len: %d", rpfx.fp_len);
     380           0 :                   continue;
     381             :                 }
     382             : 
     383          17 :               if (is_del)
     384           0 :                 fib_table_entry_path_remove2 (fib_index,
     385             :                                               &rpfx, FIB_SOURCE_CLI, rpaths);
     386             :               else
     387          17 :                 fib_table_entry_path_add2 (fib_index,
     388             :                                            &rpfx,
     389             :                                            FIB_SOURCE_CLI,
     390             :                                            FIB_ENTRY_FLAG_NONE, rpaths);
     391             : 
     392          17 :               fib_prefix_increment (&prefixs[i]);
     393             :             }
     394             : 
     395          17 :           t[1] = vlib_time_now (vm);
     396          17 :           if (count > 1)
     397           0 :             vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
     398             :         }
     399             :       else
     400             :         {
     401           0 :           error = clib_error_return (0, "Don't understand what you want...");
     402           0 :           goto done;
     403             :         }
     404             :     }
     405             : 
     406          19 : done:
     407          19 :   vec_free (dpos);
     408          19 :   vec_free (prefixs);
     409          19 :   vec_free (rpaths);
     410          19 :   unformat_free (line_input);
     411          19 :   return error;
     412             : }
     413             : 
     414             : clib_error_t *
     415           3 : vnet_ip_table_cmd (vlib_main_t * vm,
     416             :                    unformat_input_t * main_input,
     417             :                    vlib_cli_command_t * cmd, fib_protocol_t fproto)
     418             : {
     419           3 :   unformat_input_t _line_input, *line_input = &_line_input;
     420           3 :   clib_error_t *error = NULL;
     421             :   u32 table_id, is_add;
     422           3 :   u8 *name = NULL;
     423             : 
     424           3 :   is_add = 1;
     425           3 :   table_id = ~0;
     426             : 
     427             :   /* Get a line of input. */
     428           3 :   if (!unformat_user (main_input, unformat_line_input, line_input))
     429           0 :     return 0;
     430             : 
     431           7 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     432             :     {
     433           4 :       if (unformat (line_input, "%d", &table_id))
     434             :         ;
     435           1 :       else if (unformat (line_input, "del"))
     436           0 :         is_add = 0;
     437           1 :       else if (unformat (line_input, "add"))
     438           1 :         is_add = 1;
     439           0 :       else if (unformat (line_input, "name %s", &name))
     440             :         ;
     441             :       else
     442             :         {
     443           0 :           error = unformat_parse_error (line_input);
     444           0 :           goto done;
     445             :         }
     446             :     }
     447             : 
     448           3 :   if (0 == table_id)
     449             :     {
     450           0 :       error = clib_error_return (0, "Can't change the default table");
     451           0 :       goto done;
     452             :     }
     453             :   else
     454             :         {
     455           3 :           if (is_add)
     456             :             {
     457           3 :               if (~0 == table_id)
     458             :                 {
     459           0 :                   table_id = ip_table_get_unused_id (fproto);
     460           0 :                   vlib_cli_output (vm, "%u\n", table_id);
     461             :                 }
     462           3 :               ip_table_create (fproto, table_id, 0, name);
     463             :             }
     464             :           else
     465             :             {
     466           0 :               if (~0 == table_id)
     467             :                 {
     468           0 :                   error = clib_error_return (0, "No table id");
     469           0 :                   goto done;
     470             :                 }
     471           0 :               ip_table_delete (fproto, table_id, 0);
     472             :             }
     473             :         }
     474             : 
     475           3 : done:
     476           3 :   vec_free (name);
     477           3 :   unformat_free (line_input);
     478           3 :   return error;
     479             : }
     480             : 
     481             : clib_error_t *
     482           2 : vnet_ip4_table_cmd (vlib_main_t * vm,
     483             :                     unformat_input_t * main_input, vlib_cli_command_t * cmd)
     484             : {
     485           2 :   return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
     486             : }
     487             : 
     488             : clib_error_t *
     489           1 : vnet_ip6_table_cmd (vlib_main_t * vm,
     490             :                     unformat_input_t * main_input, vlib_cli_command_t * cmd)
     491             : {
     492           1 :   return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
     493             : }
     494             : 
     495             : clib_error_t *
     496           0 : vnet_show_ip_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
     497             :                         vlib_cli_command_t *cmd, fib_protocol_t fproto)
     498             : {
     499           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     500             :   fib_table_t *fib, *fibs;
     501           0 :   clib_error_t *error = NULL;
     502           0 :   u32 table_id = ~0, fib_index;
     503             :   /* Get a line of input. */
     504           0 :   if (unformat_user (main_input, unformat_line_input, line_input))
     505             :     {
     506           0 :       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     507             :         {
     508           0 :           if (unformat (line_input, "%d", &table_id))
     509             :             ;
     510             :           else
     511             :             {
     512           0 :               error = unformat_parse_error (line_input);
     513           0 :               goto done;
     514             :             }
     515             :         }
     516           0 :       unformat_free (line_input);
     517             :     }
     518             : 
     519           0 :   fibs = (fproto == FIB_PROTOCOL_IP4) ? ip4_main.fibs : ip6_main.fibs;
     520             : 
     521           0 :   if (table_id != (u32) ~0)
     522             :     {
     523           0 :       fib_index = fib_table_find (fproto, table_id);
     524           0 :       if (fib_index == (u32) ~0)
     525             :         {
     526           0 :           error = clib_error_return (0, "Couldn't find table with table_id %u",
     527             :                                      table_id);
     528           0 :           goto done;
     529             :         }
     530             : 
     531           0 :       fib = fib_table_get (fib_index, fproto);
     532           0 :       vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
     533             :                        fib->ft_table_id, fib->ft_desc);
     534             :     }
     535             :   else
     536             :     {
     537           0 :       pool_foreach (fib, fibs)
     538           0 :         vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
     539             :                          fib->ft_table_id, fib->ft_desc);
     540             :     }
     541             : 
     542           0 : done:
     543           0 :   return error;
     544             : }
     545             : 
     546             : clib_error_t *
     547           0 : vnet_show_ip4_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
     548             :                          vlib_cli_command_t *cmd)
     549             : {
     550           0 :   return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
     551             : }
     552             : 
     553             : clib_error_t *
     554           0 : vnet_show_ip6_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
     555             :                          vlib_cli_command_t *cmd)
     556             : {
     557           0 :   return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
     558             : }
     559             : 
     560             : /* *INDENT-OFF* */
     561      285289 : VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
     562             :   .path = "ip",
     563             :   .short_help = "Internet protocol (IP) commands",
     564             : };
     565             : /* *INDENT-ON* */
     566             : 
     567             : /* *INDENT-OFF* */
     568      285289 : VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
     569             :   .path = "ip6",
     570             :   .short_help = "Internet protocol version 6 (IPv6) commands",
     571             : };
     572             : /* *INDENT-ON* */
     573             : 
     574             : /* *INDENT-OFF* */
     575      285289 : VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
     576             :   .path = "show ip",
     577             :   .short_help = "Internet protocol (IP) show commands",
     578             : };
     579             : /* *INDENT-ON* */
     580             : 
     581             : /* *INDENT-OFF* */
     582      285289 : VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
     583             :   .path = "show ip6",
     584             :   .short_help = "Internet protocol version 6 (IPv6) show commands",
     585             : };
     586             : /* *INDENT-ON* */
     587             : 
     588             : /*?
     589             :  * This command is used to add or delete IPv4 or IPv6 routes. All
     590             :  * IP Addresses ('<em><dst-ip-addr>/<width></em>',
     591             :  * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
     592             :  * can be IPv4 or IPv6, but all must be of the same form in a single
     593             :  * command. To display the current set of routes, use the commands
     594             :  * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
     595             :  *
     596             :  * @cliexpar
     597             :  * Example of how to add a straight forward static route:
     598             :  * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
     599             :  * Example of how to delete a straight forward static route:
     600             :  * @cliexcmd{ip route del 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
     601             :  * Mainly for route add/del performance testing, one can add or delete
     602             :  * multiple routes by adding 'count N' to the previous item:
     603             :  * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
     604             :  * Add multiple routes for the same destination to create equal-cost multipath:
     605             :  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
     606             :  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
     607             :  * For unequal-cost multipath, specify the desired weights. This
     608             :  * combination of weights results in 3/4 of the traffic following the
     609             :  * second path, 1/4 following the first path:
     610             :  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
     611             :  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
     612             :  * To add a route to a particular FIB table (VRF), use:
     613             :  * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
     614             :  ?*/
     615             : /* *INDENT-OFF* */
     616      285289 : VLIB_CLI_COMMAND (ip_route_command, static) = {
     617             :   .path = "ip route",
     618             :   .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table "
     619             :                 "<table-id>] via [next-hop-address] [next-hop-interface] "
     620             :                 "[next-hop-table <value>] [weight <value>] [preference "
     621             :                 "<value>] [udp-encap <value>] [ip4-lookup-in-table <value>] "
     622             :                 "[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
     623             :                 "[resolve-via-host] [resolve-via-connected] [rx-ip4 "
     624             :                 "<interface>] [out-labels <value value value>]",
     625             :   .function = vnet_ip_route_cmd,
     626             :   .is_mp_safe = 1,
     627             : };
     628             : 
     629             : /* *INDENT-ON* */
     630             : /*?
     631             :  * This command is used to add or delete IPv4  Tables. All
     632             :  * Tables must be explicitly added before that can be used. Creating a
     633             :  * table will add both unicast and multicast FIBs
     634             :  *
     635             :  ?*/
     636             : /* *INDENT-OFF* */
     637      285289 : VLIB_CLI_COMMAND (ip4_table_command, static) = {
     638             :   .path = "ip table",
     639             :   .short_help = "ip table [add|del] <table-id>",
     640             :   .function = vnet_ip4_table_cmd,
     641             : };
     642             : /* *INDENT-ON* */
     643             : 
     644             : /* *INDENT-ON* */
     645             : /*?
     646             :  * This command is used to add or delete IPv4  Tables. All
     647             :  * Tables must be explicitly added before that can be used. Creating a
     648             :  * table will add both unicast and multicast FIBs
     649             :  *
     650             :  ?*/
     651             : /* *INDENT-OFF* */
     652      285289 : VLIB_CLI_COMMAND (ip6_table_command, static) = {
     653             :   .path = "ip6 table",
     654             :   .short_help = "ip6 table [add|del] <table-id>",
     655             :   .function = vnet_ip6_table_cmd,
     656             : };
     657             : 
     658      285289 : VLIB_CLI_COMMAND (show_ip4_table_command, static) = {
     659             :   .path = "show ip table",
     660             :   .short_help = "show ip table <table-id>",
     661             :   .function = vnet_show_ip4_table_cmd,
     662             : };
     663             : 
     664      285289 : VLIB_CLI_COMMAND (show_ip6_table_command, static) = {
     665             :   .path = "show ip6 table",
     666             :   .short_help = "show ip6 table <table-id>",
     667             :   .function = vnet_show_ip6_table_cmd,
     668             : };
     669             : 
     670             : static clib_error_t *
     671           2 : ip_table_bind_cmd (vlib_main_t * vm,
     672             :                    unformat_input_t * input,
     673             :                    vlib_cli_command_t * cmd,
     674             :                    fib_protocol_t fproto)
     675             : {
     676           2 :   vnet_main_t *vnm = vnet_get_main ();
     677           2 :   clib_error_t *error = 0;
     678             :   u32 sw_if_index, table_id;
     679             :   int rv;
     680             : 
     681           2 :   sw_if_index = ~0;
     682             : 
     683           2 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     684             :     {
     685           0 :       error = clib_error_return (0, "unknown interface `%U'",
     686             :                                  format_unformat_error, input);
     687           0 :       goto done;
     688             :     }
     689             : 
     690           2 :   if (unformat (input, "%d", &table_id))
     691             :     ;
     692             :   else
     693             :     {
     694           0 :       error = clib_error_return (0, "expected table id `%U'",
     695             :                                  format_unformat_error, input);
     696           0 :       goto done;
     697             :     }
     698             : 
     699           2 :   rv = ip_table_bind (fproto, sw_if_index, table_id);
     700             : 
     701           2 :   if (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE == rv)
     702             :     {
     703           0 :       error = clib_error_return (0, "IP addresses are still present on %U",
     704             :                                  format_vnet_sw_if_index_name,
     705             :                                  vnet_get_main(),
     706             :                                  sw_if_index);
     707             :     }
     708           2 :   else if (VNET_API_ERROR_NO_SUCH_FIB == rv)
     709             :     {
     710           0 :       error = clib_error_return (0, "no such table %d", table_id);
     711             :     }
     712           2 :   else if (0 != rv)
     713             :     {
     714           0 :       error = clib_error_return (0, "unknown error");
     715             :     }
     716             : 
     717           2 :  done:
     718           2 :   return error;
     719             : }
     720             : 
     721             : static clib_error_t *
     722           1 : ip4_table_bind_cmd (vlib_main_t * vm,
     723             :                     unformat_input_t * input,
     724             :                     vlib_cli_command_t * cmd)
     725             : {
     726           1 :   return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP4));
     727             : }
     728             : 
     729             : static clib_error_t *
     730           1 : ip6_table_bind_cmd (vlib_main_t * vm,
     731             :                     unformat_input_t * input,
     732             :                     vlib_cli_command_t * cmd)
     733             : {
     734           1 :   return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP6));
     735             : }
     736             : 
     737             : /*?
     738             :  * Place the indicated interface into the supplied IPv4 FIB table (also known
     739             :  * as a VRF). The FIB table must be created using "ip table add" already. To
     740             :  * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
     741             :  * FIB table will only be displayed if a route has been added to the table, or
     742             :  * an IP Address is assigned to an interface in the table (which adds a route
     743             :  * automatically).
     744             :  *
     745             :  * @note IP addresses added after setting the interface IP table are added to
     746             :  * the indicated FIB table. If an IP address is added prior to changing the
     747             :  * table then this is an error. The control plane must remove these addresses
     748             :  * first and then change the table. VPP will not automatically move the
     749             :  * addresses from the old to the new table as it does not know the validity
     750             :  * of such a change.
     751             :  *
     752             :  * @cliexpar
     753             :  * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
     754             :  * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
     755             :  ?*/
     756             : /* *INDENT-OFF* */
     757      285289 : VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
     758             : {
     759             :   .path = "set interface ip table",
     760             :   .function = ip4_table_bind_cmd,
     761             :   .short_help = "set interface ip table <interface> <table-id>",
     762             : };
     763             : /* *INDENT-ON* */
     764             : 
     765             : /*?
     766             :  * Place the indicated interface into the supplied IPv6 FIB table (also known
     767             :  * as a VRF). The FIB table must be created using "ip6 table add" already. To
     768             :  * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
     769             :  * FIB table will only be displayed if a route has been added to the table, or
     770             :  * an IP Address is assigned to an interface in the table (which adds a route
     771             :  * automatically).
     772             :  *
     773             :  * @note IP addresses added after setting the interface IP table are added to
     774             :  * the indicated FIB table. If an IP address is added prior to changing the
     775             :  * table then this is an error. The control plane must remove these addresses
     776             :  * first and then change the table. VPP will not automatically move the
     777             :  * addresses from the old to the new table as it does not know the validity
     778             :  * of such a change.
     779             :  *
     780             :  * @cliexpar
     781             :  * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
     782             :  * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
     783             :  ?*/
     784             : /* *INDENT-OFF* */
     785      285289 : VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
     786             : {
     787             :   .path = "set interface ip6 table",
     788             :   .function = ip6_table_bind_cmd,
     789             :   .short_help = "set interface ip6 table <interface> <table-id>"
     790             : };
     791             : /* *INDENT-ON* */
     792             : 
     793             : clib_error_t *
     794           0 : vnet_ip_mroute_cmd (vlib_main_t * vm,
     795             :                     unformat_input_t * main_input, vlib_cli_command_t * cmd)
     796             : {
     797           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     798           0 :   fib_route_path_t rpath, *rpaths = NULL;
     799           0 :   clib_error_t *error = NULL;
     800             :   u32 table_id, is_del, payload_proto;
     801             :   mfib_prefix_t pfx;
     802             :   u32 fib_index;
     803           0 :   mfib_entry_flags_t eflags = 0;
     804             :   u32 gcount, scount, ss, gg, incr;
     805             :   f64 timet[2];
     806           0 :   u32 rpf_id = MFIB_RPF_ID_NONE;
     807             : 
     808           0 :   gcount = scount = 1;
     809           0 :   is_del = 0;
     810           0 :   table_id = 0;
     811           0 :   clib_memset (&pfx, 0, sizeof (pfx));
     812           0 :   clib_memset (&rpath, 0, sizeof (rpath));
     813           0 :   rpath.frp_sw_if_index = ~0;
     814             : 
     815             :   /* Get a line of input. */
     816           0 :   if (!unformat_user (main_input, unformat_line_input, line_input))
     817           0 :     return 0;
     818             : 
     819           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     820             :     {
     821           0 :       if (unformat (line_input, "table %d", &table_id))
     822             :         ;
     823           0 :       else if (unformat (line_input, "del"))
     824           0 :         is_del = 1;
     825           0 :       else if (unformat (line_input, "add"))
     826           0 :         is_del = 0;
     827           0 :       else if (unformat (line_input, "rpf-id %d", &rpf_id))
     828             :         ;
     829           0 :       else if (unformat (line_input, "scount %d", &scount))
     830             :         ;
     831           0 :       else if (unformat (line_input, "gcount %d", &gcount))
     832             :         ;
     833           0 :       else if (unformat (line_input, "%U %U",
     834             :                          unformat_ip4_address,
     835             :                          &pfx.fp_src_addr.ip4,
     836             :                          unformat_ip4_address, &pfx.fp_grp_addr.ip4))
     837             :         {
     838           0 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
     839           0 :           pfx.fp_len = 64;
     840             :         }
     841           0 :       else if (unformat (line_input, "%U %U",
     842             :                          unformat_ip6_address,
     843             :                          &pfx.fp_src_addr.ip6,
     844             :                          unformat_ip6_address, &pfx.fp_grp_addr.ip6))
     845             :         {
     846           0 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
     847           0 :           pfx.fp_len = 256;
     848             :         }
     849           0 :       else if (unformat (line_input, "%U/%d",
     850             :                          unformat_ip4_address,
     851             :                          &pfx.fp_grp_addr.ip4, &pfx.fp_len))
     852             :         {
     853           0 :           clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
     854           0 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
     855             :         }
     856           0 :       else if (unformat (line_input, "%U/%d",
     857             :                          unformat_ip6_address,
     858             :                          &pfx.fp_grp_addr.ip6, &pfx.fp_len))
     859             :         {
     860           0 :           clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
     861           0 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
     862             :         }
     863           0 :       else if (unformat (line_input, "%U",
     864             :                          unformat_ip4_address, &pfx.fp_grp_addr.ip4))
     865             :         {
     866           0 :           clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
     867           0 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
     868           0 :           pfx.fp_len = 32;
     869             :         }
     870           0 :       else if (unformat (line_input, "%U",
     871             :                          unformat_ip6_address, &pfx.fp_grp_addr.ip6))
     872             :         {
     873           0 :           clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
     874           0 :           payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
     875           0 :           pfx.fp_len = 128;
     876             :         }
     877           0 :       else if (unformat (line_input, "via local Forward"))
     878             :         {
     879           0 :           clib_memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr));
     880           0 :           rpath.frp_sw_if_index = ~0;
     881           0 :           rpath.frp_weight = 1;
     882           0 :           rpath.frp_flags |= FIB_ROUTE_PATH_LOCAL;
     883             :           /*
     884             :            * set the path proto appropriately for the prefix
     885             :            */
     886           0 :           rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto);
     887           0 :           rpath.frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
     888             : 
     889           0 :           vec_add1 (rpaths, rpath);
     890             :         }
     891           0 :       else if (unformat (line_input, "via %U",
     892             :                          unformat_fib_route_path, &rpath, &payload_proto))
     893             :         {
     894           0 :           vec_add1 (rpaths, rpath);
     895             :         }
     896           0 :       else if (unformat (line_input, "%U",
     897             :                          unformat_mfib_entry_flags, &eflags))
     898             :         ;
     899             :       else
     900             :         {
     901           0 :           error = unformat_parse_error (line_input);
     902           0 :           goto done;
     903             :         }
     904             :     }
     905             : 
     906           0 :   if (~0 == table_id)
     907             :     {
     908             :       /*
     909             :        * if no table_id is passed we will manipulate the default
     910             :        */
     911           0 :       fib_index = 0;
     912             :     }
     913             :   else
     914             :     {
     915           0 :       fib_index = mfib_table_find (pfx.fp_proto, table_id);
     916             : 
     917           0 :       if (~0 == fib_index)
     918             :         {
     919           0 :           error = clib_error_return (0, "Nonexistent table id %d", table_id);
     920           0 :           goto done;
     921             :         }
     922             :     }
     923             : 
     924           0 :   timet[0] = vlib_time_now (vm);
     925             : 
     926           0 :   if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
     927             :     {
     928           0 :       incr = 1 << (32 - (pfx.fp_len % 32));
     929             :     }
     930             :   else
     931             :     {
     932           0 :       incr = 1 << (128 - (pfx.fp_len % 128));
     933             :     }
     934             : 
     935           0 :   for (ss = 0; ss < scount; ss++)
     936             :     {
     937           0 :       for (gg = 0; gg < gcount; gg++)
     938             :         {
     939           0 :           if (is_del && 0 == vec_len (rpaths))
     940             :             {
     941             :               /* no path provided => route delete */
     942           0 :               mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI);
     943             :             }
     944           0 :           else if (eflags || (MFIB_RPF_ID_NONE != rpf_id))
     945             :             {
     946           0 :               mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
     947             :                                        rpf_id, eflags);
     948             :             }
     949             :           else
     950             :             {
     951           0 :               if (is_del)
     952           0 :                 mfib_table_entry_path_remove (fib_index,
     953             :                                               &pfx, MFIB_SOURCE_CLI, rpaths);
     954             :               else
     955           0 :                 mfib_table_entry_path_update (fib_index, &pfx, MFIB_SOURCE_CLI,
     956             :                                               MFIB_ENTRY_FLAG_NONE, rpaths);
     957             :             }
     958             : 
     959           0 :           if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
     960             :             {
     961           0 :               pfx.fp_grp_addr.ip4.as_u32 =
     962           0 :                 clib_host_to_net_u32 (incr +
     963           0 :                                       clib_net_to_host_u32 (pfx.
     964             :                                                             fp_grp_addr.ip4.
     965             :                                                             as_u32));
     966             :             }
     967             :           else
     968             :             {
     969           0 :               int bucket = (incr < 64 ? 0 : 1);
     970           0 :               pfx.fp_grp_addr.ip6.as_u64[bucket] =
     971           0 :                 clib_host_to_net_u64 (incr +
     972           0 :                                       clib_net_to_host_u64 (pfx.
     973             :                                                             fp_grp_addr.ip6.as_u64
     974             :                                                             [bucket]));
     975             : 
     976             :             }
     977             :         }
     978           0 :       if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
     979             :         {
     980           0 :           pfx.fp_src_addr.ip4.as_u32 =
     981           0 :             clib_host_to_net_u32 (1 +
     982           0 :                                   clib_net_to_host_u32 (pfx.fp_src_addr.
     983             :                                                         ip4.as_u32));
     984             :         }
     985             :       else
     986             :         {
     987           0 :           pfx.fp_src_addr.ip6.as_u64[1] =
     988           0 :             clib_host_to_net_u64 (1 +
     989           0 :                                   clib_net_to_host_u64 (pfx.fp_src_addr.
     990             :                                                         ip6.as_u64[1]));
     991             :         }
     992             :     }
     993             : 
     994           0 :   timet[1] = vlib_time_now (vm);
     995             : 
     996           0 :   if (scount > 1 || gcount > 1)
     997           0 :     vlib_cli_output (vm, "%.6e routes/sec",
     998           0 :                      (scount * gcount) / (timet[1] - timet[0]));
     999             : 
    1000           0 : done:
    1001           0 :   vec_free (rpaths);
    1002           0 :   unformat_free (line_input);
    1003             : 
    1004           0 :   return error;
    1005             : }
    1006             : 
    1007             : /*?
    1008             :  * This command is used to add or delete IPv4 or IPv6  multicast routes. All
    1009             :  * IP Addresses ('<em><dst-ip-addr>/<width></em>',
    1010             :  * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
    1011             :  * can be IPv4 or IPv6, but all must be of the same form in a single
    1012             :  * command. To display the current set of routes, use the commands
    1013             :  * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'.
    1014             :  * The full set of support flags for interfaces and route is shown via;
    1015             :  * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>'
    1016             :  * respectively.
    1017             :  * @cliexpar
    1018             :  * Example of how to add a forwarding interface to a route (and create the
    1019             :  * route if it does not exist)
    1020             :  * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward}
    1021             :  * Example of how to add an accepting interface to a route (and create the
    1022             :  * route if it does not exist)
    1023             :  * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept}
    1024             :  * Example of changing the route's flags to send signals via the API
    1025             :  * @cliexcmd{ip mroute add 232.1.1.1 Signal}
    1026             : 
    1027             :  ?*/
    1028             : /* *INDENT-OFF* */
    1029      285289 : VLIB_CLI_COMMAND (ip_mroute_command, static) =
    1030             : {
    1031             :   .path = "ip mroute",
    1032             :   .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [rpf-id <ID>] [via <next-hop-ip-addr> [<interface>],",
    1033             :   .function = vnet_ip_mroute_cmd,
    1034             :   .is_mp_safe = 1,
    1035             : };
    1036             : /* *INDENT-ON* */
    1037             : 
    1038             : /*
    1039             :  * fd.io coding-style-patch-verification: ON
    1040             :  *
    1041             :  * Local Variables:
    1042             :  * eval: (c-set-style "gnu")
    1043             :  * End:
    1044             :  */

Generated by: LCOV version 1.14