LCOV - code coverage report
Current view: top level - plugins/l3xc - l3xc.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 78 125 62.4 %
Date: 2023-07-05 22:20:52 Functions: 19 21 90.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <plugins/l3xc/l3xc.h>
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/plugin/plugin.h>
      20             : #include <vnet/fib/fib_path_list.h>
      21             : 
      22             : /**
      23             :  * FIB node type the attachment is registered
      24             :  */
      25             : fib_node_type_t l3xc_fib_node_type;
      26             : 
      27             : /**
      28             :  * Pool of L3XC objects
      29             :  */
      30             : l3xc_t *l3xc_pool;
      31             : 
      32             : /**
      33             :  * DB of L3XC objects
      34             :  */
      35             : static u32 *l3xc_db[FIB_PROTOCOL_IP_MAX];
      36             : 
      37             : index_t
      38          10 : l3xc_find (u32 sw_if_index, fib_protocol_t fproto)
      39             : {
      40          10 :   if (vec_len (l3xc_db[fproto]) <= sw_if_index)
      41           5 :     return ~0;
      42             : 
      43           5 :   return (l3xc_db[fproto][sw_if_index]);
      44             : }
      45             : 
      46             : static void
      47           2 : l3xc_db_add (u32 sw_if_index, fib_protocol_t fproto, index_t l3xci)
      48             : {
      49           6 :   vec_validate_init_empty (l3xc_db[fproto], sw_if_index, ~0);
      50             : 
      51           2 :   l3xc_db[fproto][sw_if_index] = l3xci;
      52           2 : }
      53             : 
      54             : static void
      55           2 : l3xc_db_remove (u32 sw_if_index, fib_protocol_t fproto)
      56             : {
      57           2 :   vec_validate_init_empty (l3xc_db[fproto], sw_if_index, ~0);
      58             : 
      59           2 :   l3xc_db[fproto][sw_if_index] = ~0;
      60           2 : }
      61             : 
      62             : static void
      63           5 : l3xc_stack (l3xc_t * l3xc)
      64             : {
      65             :   /*
      66             :    * stack the DPO on the forwarding contributed by the path-list
      67             :    */
      68           5 :   dpo_id_t via_dpo = DPO_INVALID;
      69             : 
      70           5 :   fib_path_list_contribute_forwarding (
      71             :     l3xc->l3xc_pl,
      72           5 :     (FIB_PROTOCOL_IP4 == l3xc->l3xc_proto ? FIB_FORW_CHAIN_TYPE_UNICAST_IP4 :
      73             :                                             FIB_FORW_CHAIN_TYPE_UNICAST_IP6),
      74             :     FIB_PATH_LIST_FWD_FLAG_COLLAPSE, &via_dpo);
      75             : 
      76           5 :   dpo_stack_from_node ((FIB_PROTOCOL_IP4 == l3xc->l3xc_proto ?
      77             :                         l3xc_ip4_node.index :
      78             :                         l3xc_ip6_node.index), &l3xc->l3xc_dpo, &via_dpo);
      79           5 :   dpo_reset (&via_dpo);
      80           5 : }
      81             : 
      82             : int
      83           2 : l3xc_update (u32 sw_if_index, u8 is_ip6, const fib_route_path_t * rpaths)
      84             : {
      85             :   fib_protocol_t fproto;
      86             :   l3xc_t *l3xc;
      87             :   u32 l3xci;
      88             : 
      89           2 :   fproto = (is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
      90             : 
      91           2 :   l3xci = l3xc_find (sw_if_index, fproto);
      92             : 
      93           2 :   if (INDEX_INVALID == l3xci)
      94             :     {
      95             :       /*
      96             :        * create a new x-connect
      97             :        */
      98           2 :       pool_get_aligned_zero (l3xc_pool, l3xc, CLIB_CACHE_LINE_BYTES);
      99             : 
     100           2 :       l3xci = l3xc - l3xc_pool;
     101           2 :       fib_node_init (&l3xc->l3xc_node, l3xc_fib_node_type);
     102           2 :       l3xc->l3xc_sw_if_index = sw_if_index;
     103           2 :       l3xc->l3xc_proto = fproto;
     104             : 
     105             :       /*
     106             :        * create and become a child of a path list so we get poked when
     107             :        * the forwarding changes and stack on the DPO the path-list provides
     108             :        */
     109           2 :       l3xc->l3xc_pl = fib_path_list_create ((FIB_PATH_LIST_FLAG_SHARED |
     110             :                                              FIB_PATH_LIST_FLAG_NO_URPF),
     111             :                                             rpaths);
     112           2 :       l3xc->l3xc_sibling = fib_path_list_child_add (l3xc->l3xc_pl,
     113             :                                                     l3xc_fib_node_type,
     114             :                                                     l3xci);
     115           2 :       l3xc_stack (l3xc);
     116             : 
     117             :       /*
     118             :        * add this new policy to the DB and enable the feature on input interface
     119             :        */
     120           2 :       l3xc_db_add (sw_if_index, fproto, l3xci);
     121             : 
     122           2 :       vnet_feature_enable_disable ((FIB_PROTOCOL_IP4 == fproto ?
     123             :                                     "ip4-unicast" :
     124             :                                     "ip6-unicast"),
     125             :                                    (FIB_PROTOCOL_IP4 == fproto ?
     126             :                                     "l3xc-input-ip4" :
     127             :                                     "l3xc-input-ip6"),
     128           2 :                                    l3xc->l3xc_sw_if_index,
     129             :                                    1, &l3xci, sizeof (l3xci));
     130             :     }
     131             :   else
     132             :     {
     133             :       /*
     134             :        * update an existing x-connect.
     135             :        * - add the path to the path-list and swap our ancestry
     136             :        */
     137           0 :       l3xc = l3xc_get (l3xci);
     138             : 
     139           0 :       if (FIB_NODE_INDEX_INVALID != l3xc->l3xc_pl)
     140             :         {
     141           0 :           fib_path_list_child_remove (l3xc->l3xc_pl, l3xc->l3xc_sibling);
     142             :         }
     143             : 
     144           0 :       l3xc->l3xc_pl = fib_path_list_create ((FIB_PATH_LIST_FLAG_SHARED |
     145             :                                              FIB_PATH_LIST_FLAG_NO_URPF),
     146             :                                             rpaths);
     147             : 
     148           0 :       l3xc->l3xc_sibling = fib_path_list_child_add (l3xc->l3xc_pl,
     149             :                                                     l3xc_fib_node_type,
     150             :                                                     l3xci);
     151             :     }
     152           2 :   return (0);
     153             : }
     154             : 
     155             : int
     156           2 : l3xc_delete (u32 sw_if_index, u8 is_ip6)
     157             : {
     158             :   fib_protocol_t fproto;
     159             :   l3xc_t *l3xc;
     160             :   u32 l3xci;
     161             : 
     162           2 :   fproto = (is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
     163             : 
     164           2 :   l3xci = l3xc_find (sw_if_index, fproto);
     165             : 
     166           2 :   if (INDEX_INVALID == l3xci)
     167             :     {
     168             :       /*
     169             :        * no such policy
     170             :        */
     171           0 :       return (VNET_API_ERROR_INVALID_VALUE);
     172             :     }
     173             :   else
     174             :     {
     175           2 :       l3xc = l3xc_get (l3xci);
     176             : 
     177           2 :       vnet_feature_enable_disable ((FIB_PROTOCOL_IP4 == fproto ?
     178             :                                     "ip4-unicast" :
     179             :                                     "ip6-unicast"),
     180             :                                    (FIB_PROTOCOL_IP4 == fproto ?
     181             :                                     "l3xc-input-ip4" :
     182             :                                     "l3xc-input-ip6"),
     183             :                                    l3xc->l3xc_sw_if_index,
     184             :                                    0, &l3xci, sizeof (l3xci));
     185             : 
     186           2 :       fib_path_list_child_remove (l3xc->l3xc_pl, l3xc->l3xc_sibling);
     187           2 :       dpo_reset (&l3xc->l3xc_dpo);
     188             : 
     189           2 :       l3xc_db_remove (l3xc->l3xc_sw_if_index, fproto);
     190           2 :       pool_put (l3xc_pool, l3xc);
     191             :     }
     192             : 
     193           2 :   return (0);
     194             : }
     195             : 
     196             : static clib_error_t *
     197           0 : l3xc_cmd (vlib_main_t * vm,
     198             :           unformat_input_t * main_input, vlib_cli_command_t * cmd)
     199             : {
     200           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     201           0 :   fib_route_path_t *rpaths = NULL, rpath;
     202             :   u32 sw_if_index, is_del, is_ip6;
     203             :   dpo_proto_t payload_proto;
     204             :   vnet_main_t *vnm;
     205           0 :   int rv = 0;
     206             : 
     207           0 :   is_ip6 = is_del = 0;
     208           0 :   sw_if_index = ~0;
     209           0 :   vnm = vnet_get_main ();
     210             : 
     211             :   /* Get a line of input. */
     212           0 :   if (!unformat_user (main_input, unformat_line_input, line_input))
     213           0 :     return 0;
     214             : 
     215           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     216             :     {
     217           0 :       if (unformat
     218             :           (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
     219             :         ;
     220           0 :       else if (unformat (line_input, "ip6"))
     221           0 :         is_ip6 = 1;
     222           0 :       else if (unformat (line_input, "ip4"))
     223           0 :         is_ip6 = 0;
     224           0 :       else if (unformat (line_input, "del"))
     225           0 :         is_del = 1;
     226           0 :       else if (unformat (line_input, "add"))
     227           0 :         is_del = 0;
     228           0 :       else if (unformat (line_input, "via %U",
     229             :                          unformat_fib_route_path, &rpath, &payload_proto))
     230           0 :         vec_add1 (rpaths, rpath);
     231             :       else
     232           0 :         return (clib_error_return (0, "unknown input '%U'",
     233             :                                    format_unformat_error, line_input));
     234             :     }
     235             : 
     236           0 :   if (~0 == sw_if_index)
     237             :     {
     238           0 :       vlib_cli_output (vm, "Specify an input interface");
     239           0 :       goto out;
     240             :     }
     241           0 :   if (vec_len (rpaths) == 0)
     242             :     {
     243           0 :       vlib_cli_output (vm, "Specify some paths");
     244           0 :       goto out;
     245             :     }
     246             : 
     247           0 :   if (!is_del)
     248             :     {
     249           0 :       rv = l3xc_update (sw_if_index, is_ip6, rpaths);
     250             : 
     251           0 :       if (rv)
     252             :         {
     253           0 :           vlib_cli_output (vm, "Failed: %d", rv);
     254           0 :           goto out;
     255             :         }
     256             :     }
     257             :   else
     258             :     {
     259           0 :       l3xc_delete (sw_if_index, is_ip6);
     260             :     }
     261             : 
     262           0 : out:
     263           0 :   unformat_free (line_input);
     264           0 :   return (NULL);
     265             : }
     266             : 
     267             : /* *INDENT-OFF* */
     268             : /**
     269             :  * Create an L3XC policy.
     270             :  */
     271      170967 : VLIB_CLI_COMMAND (l3xc_cmd_node, static) = {
     272             :   .path = "l3xc",
     273             :   .function = l3xc_cmd,
     274             :   .short_help = "l3xc [add|del] <INTERFACE> via ...",
     275             :   .is_mp_safe = 1,
     276             : };
     277             : /* *INDENT-ON* */
     278             : 
     279             : static u8 *
     280           2 : format_l3xc (u8 * s, va_list * args)
     281             : {
     282           2 :   l3xc_t *l3xc = va_arg (*args, l3xc_t *);
     283           2 :   vnet_main_t *vnm = vnet_get_main ();
     284             : 
     285           2 :   s = format (s, "l3xc:[%d]: %U",
     286           2 :               l3xc - l3xc_pool, format_vnet_sw_if_index_name,
     287             :               vnm, l3xc->l3xc_sw_if_index);
     288           2 :   s = format (s, "\n");
     289           2 :   if (FIB_NODE_INDEX_INVALID == l3xc->l3xc_pl)
     290             :     {
     291           0 :       s = format (s, "no forwarding");
     292             :     }
     293             :   else
     294             :     {
     295           2 :       s = fib_path_list_format (l3xc->l3xc_pl, s);
     296             : 
     297           2 :       s = format (s, "\n  %U", format_dpo_id, &l3xc->l3xc_dpo, 4);
     298             :     }
     299             : 
     300           2 :   return (s);
     301             : }
     302             : 
     303             : void
     304           1 : l3xc_walk (l3xc_walk_cb_t cb, void *ctx)
     305             : {
     306             :   u32 l3xci;
     307             : 
     308             :   /* *INDENT-OFF* */
     309           3 :   pool_foreach_index (l3xci, l3xc_pool)
     310             :    {
     311           2 :     if (!cb(l3xci, ctx))
     312           0 :       break;
     313             :   }
     314             :   /* *INDENT-ON* */
     315           1 : }
     316             : 
     317             : static clib_error_t *
     318           1 : l3xc_show_cmd (vlib_main_t * vm,
     319             :                unformat_input_t * input, vlib_cli_command_t * cmd)
     320             : {
     321             :   l3xc_t *l3xc;
     322             : 
     323             :   /* *INDENT-OFF* */
     324           3 :   pool_foreach (l3xc, l3xc_pool)
     325             :    {
     326           2 :     vlib_cli_output(vm, "%U", format_l3xc, l3xc);
     327             :   }
     328             :   /* *INDENT-ON* */
     329             : 
     330           1 :   return (NULL);
     331             : }
     332             : 
     333             : /* *INDENT-OFF* */
     334      170967 : VLIB_CLI_COMMAND (l3xc_show_cmd_node, static) = {
     335             :   .path = "show l3xc",
     336             :   .function = l3xc_show_cmd,
     337             :   .short_help = "show l3xc",
     338             :   .is_mp_safe = 1,
     339             : };
     340             : /* *INDENT-ON* */
     341             : 
     342             : static fib_node_t *
     343           3 : l3xc_get_node (fib_node_index_t index)
     344             : {
     345           3 :   l3xc_t *l3xc = l3xc_get (index);
     346           3 :   return (&(l3xc->l3xc_node));
     347             : }
     348             : 
     349             : static l3xc_t *
     350           3 : l3xc_get_from_node (fib_node_t * node)
     351             : {
     352           3 :   return ((l3xc_t *) (((char *) node) -
     353             :                       STRUCT_OFFSET_OF (l3xc_t, l3xc_node)));
     354             : }
     355             : 
     356             : static void
     357           0 : l3xc_last_lock_gone (fib_node_t * node)
     358             : {
     359           0 : }
     360             : 
     361             : /*
     362             :  * A back walk has reached this L3XC policy
     363             :  */
     364             : static fib_node_back_walk_rc_t
     365           3 : l3xc_back_walk_notify (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
     366             : {
     367           3 :   l3xc_stack (l3xc_get_from_node (node));
     368             : 
     369           3 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     370             : }
     371             : 
     372             : /*
     373             :  * The BIER fmask's graph node virtual function table
     374             :  */
     375             : static const fib_node_vft_t l3xc_vft = {
     376             :   .fnv_get = l3xc_get_node,
     377             :   .fnv_last_lock = l3xc_last_lock_gone,
     378             :   .fnv_back_walk = l3xc_back_walk_notify,
     379             : };
     380             : 
     381             : static clib_error_t *
     382         559 : l3xc_init (vlib_main_t * vm)
     383             : {
     384         559 :   l3xc_fib_node_type = fib_node_register_new_type ("l3xc", &l3xc_vft);
     385             : 
     386         559 :   return (NULL);
     387             : }
     388             : 
     389        1119 : VLIB_INIT_FUNCTION (l3xc_init);
     390             : 
     391             : /*
     392             :  * fd.io coding-style-patch-verification: ON
     393             :  *
     394             :  * Local Variables:
     395             :  * eval: (c-set-style "gnu")
     396             :  * End:
     397             :  */

Generated by: LCOV version 1.14