LCOV - code coverage report
Current view: top level - plugins/abf - abf_policy.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 64 147 43.5 %
Date: 2023-10-26 01:39:38 Functions: 18 22 81.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 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/abf/abf_policy.h>
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/plugin/plugin.h>
      20             : #include <vnet/fib/fib_path_list.h>
      21             : #include <vnet/fib/fib_walk.h>
      22             : 
      23             : /**
      24             :  * FIB node type the attachment is registered
      25             :  */
      26             : fib_node_type_t abf_policy_fib_node_type;
      27             : 
      28             : /**
      29             :  * Pool of ABF objects
      30             :  */
      31             : static abf_policy_t *abf_policy_pool;
      32             : 
      33             : /**
      34             :  * DB of ABF policy objects
      35             :  *  - policy ID to index conversion.
      36             :  */
      37             : static uword *abf_policy_db;
      38             : 
      39             : 
      40             : abf_policy_t *
      41         179 : abf_policy_get (u32 index)
      42             : {
      43         179 :   return (pool_elt_at_index (abf_policy_pool, index));
      44             : }
      45             : 
      46             : static u32
      47          23 : abf_policy_get_index (const abf_policy_t * abf)
      48             : {
      49          23 :   return (abf - abf_policy_pool);
      50             : }
      51             : 
      52             : static abf_policy_t *
      53           0 : abf_policy_find_i (u32 policy_id)
      54             : {
      55             :   u32 api;
      56             : 
      57           0 :   api = abf_policy_find (policy_id);
      58             : 
      59           0 :   if (INDEX_INVALID != api)
      60           0 :     return (abf_policy_get (api));
      61             : 
      62           0 :   return (NULL);
      63             : }
      64             : 
      65             : u32
      66          22 : abf_policy_find (u32 policy_id)
      67             : {
      68             :   uword *p;
      69             : 
      70          22 :   p = hash_get (abf_policy_db, policy_id);
      71             : 
      72          22 :   if (NULL != p)
      73          15 :     return (p[0]);
      74             : 
      75           7 :   return (INDEX_INVALID);
      76             : }
      77             : 
      78             : 
      79             : int
      80           7 : abf_policy_update (u32 policy_id,
      81             :                    u32 acl_index, const fib_route_path_t * rpaths)
      82             : {
      83             :   abf_policy_t *ap;
      84             :   u32 api;
      85             : 
      86           7 :   api = abf_policy_find (policy_id);
      87             : 
      88           7 :   if (INDEX_INVALID == api)
      89             :     {
      90             :       /*
      91             :        * create a new policy
      92             :        */
      93           7 :       pool_get (abf_policy_pool, ap);
      94             : 
      95           7 :       api = ap - abf_policy_pool;
      96           7 :       fib_node_init (&ap->ap_node, abf_policy_fib_node_type);
      97           7 :       ap->ap_acl = acl_index;
      98           7 :       ap->ap_id = policy_id;
      99           7 :       ap->ap_pl = fib_path_list_create ((FIB_PATH_LIST_FLAG_SHARED |
     100             :                                          FIB_PATH_LIST_FLAG_NO_URPF), rpaths);
     101             : 
     102             :       /*
     103             :        * become a child of the path list so we get poked when
     104             :        * the forwarding changes.
     105             :        */
     106           7 :       ap->ap_sibling = fib_path_list_child_add (ap->ap_pl,
     107             :                                                 abf_policy_fib_node_type,
     108             :                                                 api);
     109             : 
     110             :       /*
     111             :        * add this new policy to the DB
     112             :        */
     113           7 :       hash_set (abf_policy_db, policy_id, api);
     114             : 
     115             :       /*
     116             :        * take a lock on behalf of the CLI/API creation
     117             :        */
     118           7 :       fib_node_lock (&ap->ap_node);
     119             :     }
     120             :   else
     121             :     {
     122             :       /*
     123             :        * update an existing policy.
     124             :        * - add the path to the path-list and swap our ancestry
     125             :        * - backwalk to poke all attachments to update
     126             :        */
     127             :       fib_node_index_t old_pl;
     128             : 
     129           0 :       ap = abf_policy_get (api);
     130           0 :       old_pl = ap->ap_pl;
     131           0 :       if (ap->ap_acl != acl_index)
     132             :         {
     133             :           /* Should change this error code to something more descriptive */
     134           0 :           return (VNET_API_ERROR_INVALID_VALUE);
     135             :         }
     136             : 
     137           0 :       if (FIB_NODE_INDEX_INVALID != old_pl)
     138             :         {
     139           0 :           ap->ap_pl = fib_path_list_copy_and_path_add (old_pl,
     140             :                                                        (FIB_PATH_LIST_FLAG_SHARED
     141             :                                                         |
     142             :                                                         FIB_PATH_LIST_FLAG_NO_URPF),
     143             :                                                        rpaths);
     144           0 :           fib_path_list_child_remove (old_pl, ap->ap_sibling);
     145             :         }
     146             :       else
     147             :         {
     148           0 :           ap->ap_pl = fib_path_list_create ((FIB_PATH_LIST_FLAG_SHARED |
     149             :                                              FIB_PATH_LIST_FLAG_NO_URPF),
     150             :                                             rpaths);
     151             :         }
     152             : 
     153           0 :       ap->ap_sibling = fib_path_list_child_add (ap->ap_pl,
     154             :                                                 abf_policy_fib_node_type,
     155             :                                                 api);
     156             : 
     157           0 :       fib_node_back_walk_ctx_t ctx = {
     158             :         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
     159             :       };
     160             : 
     161           0 :       fib_walk_sync (abf_policy_fib_node_type, api, &ctx);
     162             :     }
     163           7 :   return (0);
     164             : }
     165             : 
     166             : static void
     167           7 : abf_policy_destroy (abf_policy_t * ap)
     168             : {
     169             :   /*
     170             :    * this ABF should not be a sibling on the path list, since
     171             :    * that was removed when the API config went
     172             :    */
     173           7 :   ASSERT (ap->ap_sibling == ~0);
     174           7 :   ASSERT (ap->ap_pl == FIB_NODE_INDEX_INVALID);
     175             : 
     176           7 :   hash_unset (abf_policy_db, ap->ap_id);
     177           7 :   pool_put (abf_policy_pool, ap);
     178           7 : }
     179             : 
     180             : int
     181           7 : abf_policy_delete (u32 policy_id, const fib_route_path_t * rpaths)
     182             : {
     183             :   abf_policy_t *ap;
     184             :   u32 api;
     185             : 
     186           7 :   api = abf_policy_find (policy_id);
     187             : 
     188           7 :   if (INDEX_INVALID == api)
     189             :     {
     190             :       /*
     191             :        * no such policy
     192             :        */
     193           0 :       return (VNET_API_ERROR_INVALID_VALUE);
     194             :     }
     195             : 
     196             :   /*
     197             :    * update an existing policy.
     198             :    * - add the path to the path-list and swap our ancestry
     199             :    * - backwalk to poke all attachments to update
     200             :    */
     201             :   fib_node_index_t old_pl;
     202             : 
     203           7 :   ap = abf_policy_get (api);
     204           7 :   old_pl = ap->ap_pl;
     205             : 
     206           7 :   fib_path_list_lock (old_pl);
     207           7 :   ap->ap_pl = fib_path_list_copy_and_path_remove (
     208             :     ap->ap_pl, (FIB_PATH_LIST_FLAG_SHARED | FIB_PATH_LIST_FLAG_NO_URPF),
     209             :     rpaths);
     210             : 
     211           7 :   fib_path_list_child_remove (old_pl, ap->ap_sibling);
     212           7 :   ap->ap_sibling = ~0;
     213             : 
     214           7 :   if (FIB_NODE_INDEX_INVALID == ap->ap_pl)
     215             :     {
     216             :       /*
     217             :        * no more paths on this policy. It's toast
     218             :        * remove the CLI/API's lock
     219             :        */
     220           7 :       fib_node_unlock (&ap->ap_node);
     221             :     }
     222             :   else
     223             :     {
     224           0 :       ap->ap_sibling =
     225           0 :         fib_path_list_child_add (ap->ap_pl, abf_policy_fib_node_type, api);
     226             : 
     227           0 :       fib_node_back_walk_ctx_t ctx = {
     228             :         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
     229             :       };
     230             : 
     231           0 :       fib_walk_sync (abf_policy_fib_node_type, api, &ctx);
     232             :     }
     233           7 :   fib_path_list_unlock (old_pl);
     234             : 
     235           7 :   return (0);
     236             : }
     237             : 
     238             : static clib_error_t *
     239           0 : abf_policy_cmd (vlib_main_t * vm,
     240             :                 unformat_input_t * main_input, vlib_cli_command_t * cmd)
     241             : {
     242           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     243           0 :   fib_route_path_t *rpaths = NULL, rpath;
     244             :   u32 acl_index, policy_id, is_del;
     245             :   dpo_proto_t payload_proto;
     246           0 :   int rv = 0;
     247             : 
     248           0 :   is_del = 0;
     249           0 :   acl_index = INDEX_INVALID;
     250           0 :   policy_id = INDEX_INVALID;
     251             : 
     252             :   /* Get a line of input. */
     253           0 :   if (!unformat_user (main_input, unformat_line_input, line_input))
     254           0 :     return 0;
     255             : 
     256           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     257             :     {
     258           0 :       if (unformat (line_input, "acl %d", &acl_index))
     259             :         ;
     260           0 :       else if (unformat (line_input, "id %d", &policy_id))
     261             :         ;
     262           0 :       else if (unformat (line_input, "del"))
     263           0 :         is_del = 1;
     264           0 :       else if (unformat (line_input, "add"))
     265           0 :         is_del = 0;
     266           0 :       else if (unformat (line_input, "via %U",
     267             :                          unformat_fib_route_path, &rpath, &payload_proto))
     268           0 :         vec_add1 (rpaths, rpath);
     269             :       else
     270             :         {
     271             :           clib_error_t *err;
     272           0 :           err = clib_error_return (0, "unknown input '%U'",
     273             :                                    format_unformat_error, line_input);
     274           0 :           unformat_free (line_input);
     275           0 :           return err;
     276             :         }
     277             :     }
     278             : 
     279           0 :   if (INDEX_INVALID == policy_id)
     280             :     {
     281           0 :       vlib_cli_output (vm, "Specify a Policy ID");
     282           0 :       goto out;
     283             :     }
     284             : 
     285           0 :   if (vec_len (rpaths) == 0)
     286             :     {
     287           0 :       vlib_cli_output (vm, "Hop path must not be empty");
     288           0 :       goto out;
     289             :     }
     290             : 
     291           0 :   if (!is_del)
     292             :     {
     293           0 :       if (INDEX_INVALID == acl_index)
     294             :         {
     295           0 :           vlib_cli_output (vm, "ACL index must be set");
     296           0 :           goto out;
     297             :         }
     298             : 
     299           0 :       rv = abf_policy_update (policy_id, acl_index, rpaths);
     300             :       /* Should change this error code to something more descriptive */
     301           0 :       if (rv == VNET_API_ERROR_INVALID_VALUE)
     302             :         {
     303           0 :           vlib_cli_output (vm,
     304             :                            "ACL index must match existing ACL index in policy");
     305           0 :           goto out;
     306             :         }
     307             :     }
     308             :   else
     309             :     {
     310           0 :       abf_policy_delete (policy_id, rpaths);
     311             :     }
     312             : 
     313           0 : out:
     314           0 :   unformat_free (line_input);
     315           0 :   return (NULL);
     316             : }
     317             : 
     318             : /* *INDENT-OFF* */
     319             : /**
     320             :  * Create an ABF policy.
     321             :  */
     322      282985 : VLIB_CLI_COMMAND (abf_policy_cmd_node, static) = {
     323             :   .path = "abf policy",
     324             :   .function = abf_policy_cmd,
     325             :   .short_help = "abf policy [add|del] id <index> acl <index> via ...",
     326             :   .is_mp_safe = 1,
     327             : };
     328             : /* *INDENT-ON* */
     329             : 
     330             : static u8 *
     331           0 : format_abf (u8 * s, va_list * args)
     332             : {
     333           0 :   abf_policy_t *ap = va_arg (*args, abf_policy_t *);
     334             : 
     335           0 :   s = format (s, "abf:[%d]: policy:%d acl:%d",
     336           0 :               ap - abf_policy_pool, ap->ap_id, ap->ap_acl);
     337           0 :   s = format (s, "\n ");
     338           0 :   if (FIB_NODE_INDEX_INVALID == ap->ap_pl)
     339             :     {
     340           0 :       s = format (s, "no forwarding");
     341             :     }
     342             :   else
     343             :     {
     344           0 :       s = fib_path_list_format (ap->ap_pl, s);
     345             :     }
     346             : 
     347           0 :   return (s);
     348             : }
     349             : 
     350             : void
     351          14 : abf_policy_walk (abf_policy_walk_cb_t cb, void *ctx)
     352             : {
     353             :   u32 api;
     354             : 
     355             :   /* *INDENT-OFF* */
     356          33 :   pool_foreach_index (api, abf_policy_pool)
     357             :    {
     358          19 :     if (!cb(api, ctx))
     359           0 :       break;
     360             :   }
     361             :   /* *INDENT-ON* */
     362          14 : }
     363             : 
     364             : static clib_error_t *
     365           0 : abf_show_policy_cmd (vlib_main_t * vm,
     366             :                      unformat_input_t * input, vlib_cli_command_t * cmd)
     367             : {
     368             :   u32 policy_id;
     369             :   abf_policy_t *ap;
     370             : 
     371           0 :   policy_id = INDEX_INVALID;
     372             : 
     373           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     374             :     {
     375           0 :       if (unformat (input, "%d", &policy_id))
     376             :         ;
     377             :       else
     378           0 :         return (clib_error_return (0, "unknown input '%U'",
     379             :                                    format_unformat_error, input));
     380             :     }
     381             : 
     382           0 :   if (INDEX_INVALID == policy_id)
     383             :     {
     384             :       /* *INDENT-OFF* */
     385           0 :       pool_foreach (ap, abf_policy_pool)
     386             :        {
     387           0 :         vlib_cli_output(vm, "%U", format_abf, ap);
     388             :       }
     389             :       /* *INDENT-ON* */
     390             :     }
     391             :   else
     392             :     {
     393           0 :       ap = abf_policy_find_i (policy_id);
     394             : 
     395           0 :       if (NULL != ap)
     396           0 :         vlib_cli_output (vm, "%U", format_abf, ap);
     397             :       else
     398           0 :         vlib_cli_output (vm, "Invalid policy ID:%d", policy_id);
     399             :     }
     400             : 
     401           0 :   return (NULL);
     402             : }
     403             : 
     404             : /* *INDENT-OFF* */
     405      282985 : VLIB_CLI_COMMAND (abf_policy_show_policy_cmd_node, static) = {
     406             :   .path = "show abf policy",
     407             :   .function = abf_show_policy_cmd,
     408             :   .short_help = "show abf policy <value>",
     409             :   .is_mp_safe = 1,
     410             : };
     411             : /* *INDENT-ON* */
     412             : 
     413             : static fib_node_t *
     414         102 : abf_policy_get_node (fib_node_index_t index)
     415             : {
     416         102 :   abf_policy_t *ap = abf_policy_get (index);
     417         102 :   return (&(ap->ap_node));
     418             : }
     419             : 
     420             : static abf_policy_t *
     421          30 : abf_policy_get_from_node (fib_node_t * node)
     422             : {
     423          30 :   return ((abf_policy_t *) (((char *) node) -
     424             :                             STRUCT_OFFSET_OF (abf_policy_t, ap_node)));
     425             : }
     426             : 
     427             : static void
     428           7 : abf_policy_last_lock_gone (fib_node_t * node)
     429             : {
     430           7 :   abf_policy_destroy (abf_policy_get_from_node (node));
     431           7 : }
     432             : 
     433             : /*
     434             :  * A back walk has reached this ABF policy
     435             :  */
     436             : static fib_node_back_walk_rc_t
     437          23 : abf_policy_back_walk_notify (fib_node_t * node,
     438             :                              fib_node_back_walk_ctx_t * ctx)
     439             : {
     440             :   /*
     441             :    * re-stack the fmask on the n-eos of the via
     442             :    */
     443          23 :   abf_policy_t *abf = abf_policy_get_from_node (node);
     444             : 
     445             :   /*
     446             :    * propagate further up the graph.
     447             :    * we can do this synchronously since the fan out is small.
     448             :    */
     449          23 :   fib_walk_sync (abf_policy_fib_node_type, abf_policy_get_index (abf), ctx);
     450             : 
     451          23 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     452             : }
     453             : 
     454             : /*
     455             :  * The BIER fmask's graph node virtual function table
     456             :  */
     457             : static const fib_node_vft_t abf_policy_vft = {
     458             :   .fnv_get = abf_policy_get_node,
     459             :   .fnv_last_lock = abf_policy_last_lock_gone,
     460             :   .fnv_back_walk = abf_policy_back_walk_notify,
     461             : };
     462             : 
     463             : static clib_error_t *
     464         575 : abf_policy_init (vlib_main_t * vm)
     465             : {
     466         575 :   abf_policy_fib_node_type =
     467         575 :     fib_node_register_new_type ("abf-policy", &abf_policy_vft);
     468             : 
     469         575 :   return (NULL);
     470             : }
     471             : 
     472        2303 : VLIB_INIT_FUNCTION (abf_policy_init);
     473             : 
     474             : /*
     475             :  * fd.io coding-style-patch-verification: ON
     476             :  *
     477             :  * Local Variables:
     478             :  * eval: (c-set-style "gnu")
     479             :  * End:
     480             :  */

Generated by: LCOV version 1.14