LCOV - code coverage report
Current view: top level - vnet/mpls - mpls_api.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 186 196 94.9 %
Date: 2023-07-05 22:20:52 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * mpls_api.c - mpls api
       4             :  *
       5             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at:
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  *------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include <vnet/vnet.h>
      21             : #include <vlibmemory/api.h>
      22             : 
      23             : #include <vnet/interface.h>
      24             : #include <vnet/api_errno.h>
      25             : #include <vnet/mpls/mpls.h>
      26             : #include <vnet/mpls/mpls_tunnel.h>
      27             : #include <vnet/fib/fib_table.h>
      28             : #include <vnet/fib/fib_api.h>
      29             : #include <vnet/fib/mpls_fib.h>
      30             : #include <vnet/fib/fib_path_list.h>
      31             : #include <vnet/ip/ip_types_api.h>
      32             : 
      33             : #include <vnet/format_fns.h>
      34             : #include <vnet/mpls/mpls.api_enum.h>
      35             : #include <vnet/mpls/mpls.api_types.h>
      36             : 
      37             : #define REPLY_MSG_ID_BASE mpls_main.msg_id_base
      38             : #include <vlibapi/api_helper_macros.h>
      39             : 
      40             : void
      41          44 : mpls_table_delete (u32 table_id, u8 is_api)
      42             : {
      43             :   u32 fib_index;
      44             : 
      45             :   /*
      46             :    * The MPLS defult table must also be explicitly created via the API.
      47             :    * So in contrast to IP, it gets no special treatment here.
      48             :    *
      49             :    * The API holds only one lock on the table.
      50             :    * i.e. it can be added many times via the API but needs to be
      51             :    * deleted only once.
      52             :    */
      53          44 :   fib_index = fib_table_find (FIB_PROTOCOL_MPLS, table_id);
      54             : 
      55          44 :   if (~0 != fib_index)
      56             :     {
      57          44 :       fib_table_unlock (fib_index,
      58             :                         FIB_PROTOCOL_MPLS,
      59             :                         (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI));
      60             :     }
      61          44 : }
      62             : 
      63             : void
      64          82 : vl_api_mpls_table_add_del_t_handler (vl_api_mpls_table_add_del_t * mp)
      65             : {
      66             :   vl_api_mpls_table_add_del_reply_t *rmp;
      67             :   vnet_main_t *vnm;
      68          82 :   int rv = 0;
      69             : 
      70          82 :   vnm = vnet_get_main ();
      71          82 :   vnm->api_errno = 0;
      72             : 
      73          82 :   if (mp->mt_is_add)
      74          41 :     mpls_table_create (ntohl (mp->mt_table.mt_table_id),
      75          41 :                        1, mp->mt_table.mt_name);
      76             :   else
      77          41 :     mpls_table_delete (ntohl (mp->mt_table.mt_table_id), 1);
      78             : 
      79             :   // NB: Nothing sets rv; none of the above returns an error
      80             : 
      81          82 :   REPLY_MACRO (VL_API_MPLS_TABLE_ADD_DEL_REPLY);
      82             : }
      83             : 
      84             : static int
      85         278 : mpls_ip_bind_unbind_handler (vnet_main_t * vnm,
      86             :                              vl_api_mpls_ip_bind_unbind_t * mp)
      87             : {
      88             :   u32 mpls_fib_index, ip_fib_index;
      89             :   fib_prefix_t pfx;
      90             : 
      91             :   mpls_fib_index =
      92         278 :     fib_table_find (FIB_PROTOCOL_MPLS, ntohl (mp->mb_mpls_table_id));
      93             : 
      94         278 :   if (~0 == mpls_fib_index)
      95             :     {
      96           0 :       return VNET_API_ERROR_NO_SUCH_FIB;
      97             :     }
      98             : 
      99         278 :   ip_prefix_decode (&mp->mb_prefix, &pfx);
     100             : 
     101         278 :   ip_fib_index = fib_table_find (pfx.fp_proto, ntohl (mp->mb_ip_table_id));
     102         278 :   if (~0 == ip_fib_index)
     103           0 :     return VNET_API_ERROR_NO_SUCH_FIB;
     104             : 
     105         278 :   if (mp->mb_is_bind)
     106         139 :     fib_table_entry_local_label_add (ip_fib_index, &pfx,
     107             :                                      ntohl (mp->mb_label));
     108             :   else
     109         139 :     fib_table_entry_local_label_remove (ip_fib_index, &pfx,
     110             :                                         ntohl (mp->mb_label));
     111             : 
     112         278 :   return (0);
     113             : }
     114             : 
     115             : void
     116         278 : vl_api_mpls_ip_bind_unbind_t_handler (vl_api_mpls_ip_bind_unbind_t * mp)
     117             : {
     118             :   vl_api_mpls_ip_bind_unbind_reply_t *rmp;
     119             :   vnet_main_t *vnm;
     120             :   int rv;
     121             : 
     122         278 :   vnm = vnet_get_main ();
     123         278 :   vnm->api_errno = 0;
     124             : 
     125         278 :   rv = mpls_ip_bind_unbind_handler (vnm, mp);
     126         278 :   rv = (rv == 0) ? vnm->api_errno : rv;
     127             : 
     128         278 :   REPLY_MACRO (VL_API_MPLS_IP_BIND_UNBIND_REPLY);
     129             : }
     130             : 
     131             : static int
     132          66 : mpls_route_add_del_t_handler (vnet_main_t * vnm,
     133             :                               vl_api_mpls_route_add_del_t * mp,
     134             :                               u32 * stats_index)
     135             : {
     136          66 :   fib_route_path_t *rpaths = NULL, *rpath;
     137             :   vl_api_fib_path_t *apath;
     138             :   u32 fib_index;
     139             :   int rv, ii;
     140             : 
     141          66 :   fib_prefix_t pfx = {
     142             :     .fp_len = 21,
     143             :     .fp_proto = FIB_PROTOCOL_MPLS,
     144          66 :     .fp_eos = mp->mr_route.mr_eos,
     145          66 :     .fp_label = ntohl (mp->mr_route.mr_label),
     146             :   };
     147          66 :   if (pfx.fp_eos)
     148             :     {
     149          52 :       pfx.fp_payload_proto = mp->mr_route.mr_eos_proto;
     150             :     }
     151             :   else
     152             :     {
     153          14 :       pfx.fp_payload_proto = DPO_PROTO_MPLS;
     154             :     }
     155             : 
     156          66 :   rv = fib_api_table_id_decode (FIB_PROTOCOL_MPLS,
     157             :                                 ntohl (mp->mr_route.mr_table_id), &fib_index);
     158          66 :   if (0 != rv)
     159           0 :     goto out;
     160             : 
     161          66 :   vec_validate (rpaths, mp->mr_route.mr_n_paths - 1);
     162             : 
     163         138 :   for (ii = 0; ii < mp->mr_route.mr_n_paths; ii++)
     164             :     {
     165          72 :       apath = &mp->mr_route.mr_paths[ii];
     166          72 :       rpath = &rpaths[ii];
     167             : 
     168          72 :       rv = fib_api_path_decode (apath, rpath);
     169             : 
     170          72 :       if (0 != rv)
     171           0 :         goto out;
     172             :     }
     173             : 
     174          66 :   rv = fib_api_route_add_del (
     175          66 :     mp->mr_is_add, mp->mr_is_multipath, fib_index, &pfx, FIB_SOURCE_API,
     176          66 :     (mp->mr_route.mr_is_multicast ? FIB_ENTRY_FLAG_MULTICAST :
     177             :                                     FIB_ENTRY_FLAG_NONE),
     178             :     rpaths);
     179             : 
     180          66 :   if (mp->mr_is_add && 0 == rv)
     181          33 :     *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
     182             : 
     183          33 : out:
     184          66 :   vec_free (rpaths);
     185             : 
     186          66 :   return (rv);
     187             : }
     188             : 
     189             : void
     190          66 : vl_api_mpls_route_add_del_t_handler (vl_api_mpls_route_add_del_t * mp)
     191             : {
     192             :   vl_api_mpls_route_add_del_reply_t *rmp;
     193             :   vnet_main_t *vnm;
     194             :   u32 stats_index;
     195             :   int rv;
     196             : 
     197          66 :   vnm = vnet_get_main ();
     198          66 :   stats_index = ~0;
     199             : 
     200          66 :   rv = mpls_route_add_del_t_handler (vnm, mp, &stats_index);
     201             : 
     202             :   /* *INDENT-OFF* */
     203          66 :   REPLY_MACRO2 (VL_API_MPLS_ROUTE_ADD_DEL_REPLY,
     204             :   ({
     205             :     rmp->stats_index = htonl (stats_index);
     206             :   }));
     207             :   /* *INDENT-ON* */
     208             : }
     209             : 
     210             : void
     211          44 : mpls_table_create (u32 table_id, u8 is_api, const u8 * name)
     212             : {
     213             :   /*
     214             :    * The MPLS defult table must also be explicitly created via the API.
     215             :    * So in contrast to IP, it gets no special treatment here.
     216             :    */
     217             : 
     218             :   /*
     219             :    * The API holds only one lock on the table.
     220             :    * i.e. it can be added many times via the API but needs to be
     221             :    * deleted only once.
     222             :    */
     223          44 :       fib_table_find_or_create_and_lock_w_name (FIB_PROTOCOL_MPLS,
     224             :                                                 table_id,
     225             :                                                 (is_api ?
     226             :                                                  FIB_SOURCE_API :
     227             :                                                  FIB_SOURCE_CLI), name);
     228          44 : }
     229             : 
     230             : static void
     231         418 : vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp)
     232             : {
     233         418 :   u32 tunnel_sw_if_index = ~0, tunnel_index = ~0;
     234             :   vl_api_mpls_tunnel_add_del_reply_t *rmp;
     235         418 :   fib_route_path_t *rpath, *rpaths = NULL;
     236         418 :   int ii, rv = 0;
     237             : 
     238         418 :   vec_validate (rpaths, mp->mt_tunnel.mt_n_paths - 1);
     239             : 
     240         838 :   for (ii = 0; ii < mp->mt_tunnel.mt_n_paths; ii++)
     241             :     {
     242         420 :       rpath = &rpaths[ii];
     243             : 
     244         420 :       rv = fib_api_path_decode (&mp->mt_tunnel.mt_paths[ii], rpath);
     245             : 
     246         420 :       if (0 != rv)
     247           0 :         goto out;
     248             :     }
     249         418 :   tunnel_sw_if_index = ntohl (mp->mt_tunnel.mt_sw_if_index);
     250             : 
     251         418 :   if (mp->mt_is_add)
     252             :     {
     253         209 :       if (~0 == tunnel_sw_if_index)
     254             :         tunnel_sw_if_index =
     255         209 :           vnet_mpls_tunnel_create (mp->mt_tunnel.mt_l2_only,
     256         209 :                                    mp->mt_tunnel.mt_is_multicast,
     257         209 :                                    mp->mt_tunnel.mt_tag);
     258         209 :       vnet_mpls_tunnel_path_add (tunnel_sw_if_index, rpaths);
     259             : 
     260         209 :       tunnel_index = vnet_mpls_tunnel_get_index (tunnel_sw_if_index);
     261             :     }
     262             :   else
     263             :     {
     264         209 :       tunnel_index = vnet_mpls_tunnel_get_index (tunnel_sw_if_index);
     265         209 :       tunnel_sw_if_index = ntohl (mp->mt_tunnel.mt_sw_if_index);
     266         209 :       if (!vnet_mpls_tunnel_path_remove (tunnel_sw_if_index, rpaths))
     267         209 :         vnet_mpls_tunnel_del (tunnel_sw_if_index);
     268             :     }
     269             : 
     270         418 :   vec_free (rpaths);
     271             : 
     272         418 : out:
     273             :   /* *INDENT-OFF* */
     274         418 :   REPLY_MACRO2(VL_API_MPLS_TUNNEL_ADD_DEL_REPLY,
     275             :   ({
     276             :     rmp->sw_if_index = ntohl(tunnel_sw_if_index);
     277             :     rmp->tunnel_index = ntohl(tunnel_index);
     278             :   }));
     279             :   /* *INDENT-ON* */
     280             : }
     281             : 
     282             : static void
     283         270 :   vl_api_sw_interface_set_mpls_enable_t_handler
     284             :   (vl_api_sw_interface_set_mpls_enable_t * mp)
     285             : {
     286             :   vl_api_sw_interface_set_mpls_enable_reply_t *rmp;
     287         270 :   int rv = 0;
     288             : 
     289         270 :   VALIDATE_SW_IF_INDEX (mp);
     290             : 
     291         270 :   rv = mpls_sw_interface_enable_disable (&mpls_main, ntohl (mp->sw_if_index),
     292         270 :                                          mp->enable);
     293             : 
     294         270 :   BAD_SW_IF_INDEX_LABEL;
     295         270 :   REPLY_MACRO (VL_API_SW_INTERFACE_SET_MPLS_ENABLE_REPLY);
     296             : }
     297             : 
     298             : typedef struct mpls_tunnel_send_walk_ctx_t_
     299             : {
     300             :   vl_api_registration_t *reg;
     301             :   u32 sw_if_index;
     302             :   u32 context;
     303             : } mpls_tunnel_send_walk_ctx_t;
     304             : 
     305             : static void
     306       40009 : send_mpls_tunnel_entry (u32 mti, void *arg)
     307             : {
     308             :   mpls_tunnel_send_walk_ctx_t *ctx;
     309             :   vl_api_mpls_tunnel_details_t *mp;
     310       40009 :   fib_path_encode_ctx_t path_ctx = {
     311             :     .rpaths = NULL,
     312             :   };
     313             :   const mpls_tunnel_t *mt;
     314             :   fib_route_path_t *rpath;
     315             :   vl_api_fib_path_t *fp;
     316             :   u32 n;
     317             : 
     318       40009 :   ctx = arg;
     319             : 
     320       40009 :   mt = mpls_tunnel_get (mti);
     321             : 
     322       40009 :   if (~0 != ctx->sw_if_index && mt->mt_sw_if_index != ctx->sw_if_index)
     323           0 :     return;
     324             : 
     325       40009 :   n = fib_path_list_get_n_paths (mt->mt_path_list);
     326             : 
     327       40009 :   mp = vl_msg_api_alloc (sizeof (*mp) + n * sizeof (vl_api_fib_path_t));
     328       40009 :   clib_memset (mp, 0, sizeof (*mp) + n * sizeof (vl_api_fib_path_t));
     329             : 
     330       40009 :   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_TUNNEL_DETAILS);
     331       40009 :   mp->context = ctx->context;
     332             : 
     333       40009 :   mp->mt_tunnel.mt_n_paths = n;
     334       40009 :   mp->mt_tunnel.mt_sw_if_index = ntohl (mt->mt_sw_if_index);
     335       40009 :   mp->mt_tunnel.mt_tunnel_index = ntohl (mti);
     336       40009 :   mp->mt_tunnel.mt_l2_only = ! !(MPLS_TUNNEL_FLAG_L2 & mt->mt_flags);
     337       40009 :   mp->mt_tunnel.mt_is_multicast = ! !(MPLS_TUNNEL_FLAG_MCAST & mt->mt_flags);
     338       40009 :   memcpy (mp->mt_tunnel.mt_tag, mt->mt_tag, sizeof (mp->mt_tunnel.mt_tag));
     339             : 
     340       40009 :   fib_path_list_walk_w_ext (mt->mt_path_list,
     341             :                             &mt->mt_path_exts, fib_path_encode, &path_ctx);
     342             : 
     343       40009 :   fp = mp->mt_tunnel.mt_paths;
     344       80019 :   vec_foreach (rpath, path_ctx.rpaths)
     345             :   {
     346       40010 :     fib_api_path_encode (rpath, fp);
     347       40010 :     fp++;
     348             :   }
     349             : 
     350       40009 :   vl_api_send_msg (ctx->reg, (u8 *) mp);
     351             : 
     352       40009 :   vec_free (path_ctx.rpaths);
     353             : }
     354             : 
     355             : static void
     356         416 : vl_api_mpls_tunnel_dump_t_handler (vl_api_mpls_tunnel_dump_t * mp)
     357             : {
     358             :   vl_api_registration_t *reg;
     359             : 
     360         416 :   reg = vl_api_client_index_to_registration (mp->client_index);
     361         416 :   if (!reg)
     362           0 :     return;
     363             : 
     364         416 :   mpls_tunnel_send_walk_ctx_t ctx = {
     365             :     .reg = reg,
     366         416 :     .sw_if_index = ntohl (mp->sw_if_index),
     367         416 :     .context = mp->context,
     368             :   };
     369         416 :   mpls_tunnel_walk (send_mpls_tunnel_entry, &ctx);
     370             : }
     371             : 
     372             : static void
     373          41 : send_mpls_table_details (vpe_api_main_t * am,
     374             :                          vl_api_registration_t * reg,
     375             :                          u32 context, const fib_table_t * table)
     376             : {
     377             :   vl_api_mpls_table_details_t *mp;
     378             : 
     379          41 :   mp = vl_msg_api_alloc (sizeof (*mp));
     380          41 :   memset (mp, 0, sizeof (*mp));
     381          41 :   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_TABLE_DETAILS);
     382          41 :   mp->context = context;
     383             : 
     384          41 :   mp->mt_table.mt_table_id = htonl (table->ft_table_id);
     385          41 :   memcpy (mp->mt_table.mt_name,
     386          41 :           table->ft_desc,
     387          41 :           clib_min (vec_len (table->ft_desc), sizeof (mp->mt_table.mt_name)));
     388             : 
     389          41 :   vl_api_send_msg (reg, (u8 *) mp);
     390          41 : }
     391             : 
     392             : static void
     393          82 : vl_api_mpls_table_dump_t_handler (vl_api_mpls_table_dump_t * mp)
     394             : {
     395          82 :   vpe_api_main_t *am = &vpe_api_main;
     396             :   vl_api_registration_t *reg;
     397          82 :   mpls_main_t *mm = &mpls_main;
     398             :   fib_table_t *fib_table;
     399             : 
     400          82 :   reg = vl_api_client_index_to_registration (mp->client_index);
     401          82 :   if (!reg)
     402           0 :     return;
     403             : 
     404             :   /* *INDENT-OFF* */
     405         123 :   pool_foreach (fib_table, mm->fibs)
     406             :    {
     407          41 :     send_mpls_table_details(am, reg, mp->context, fib_table);
     408             :   }
     409             :   /* *INDENT-ON* */
     410             : }
     411             : 
     412             : static void
     413       20057 : send_mpls_route_details (vpe_api_main_t * am,
     414             :                          vl_api_registration_t * reg,
     415             :                          u32 context, fib_node_index_t fib_entry_index)
     416             : {
     417             :   fib_route_path_t *rpaths, *rpath;
     418             :   vl_api_mpls_route_details_t *mp;
     419             :   const fib_prefix_t *pfx;
     420             :   vl_api_fib_path_t *fp;
     421             :   int path_count;
     422             : 
     423       20057 :   rpaths = fib_entry_encode (fib_entry_index);
     424       20057 :   pfx = fib_entry_get_prefix (fib_entry_index);
     425             : 
     426       20057 :   path_count = vec_len (rpaths);
     427       20057 :   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
     428       20057 :   if (!mp)
     429           0 :     return;
     430       20057 :   clib_memset (mp, 0, sizeof (*mp));
     431       20057 :   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_ROUTE_DETAILS);
     432       20057 :   mp->context = context;
     433             : 
     434       20057 :   mp->mr_route.mr_table_id =
     435       20057 :     htonl (fib_table_get_table_id
     436       20057 :            (fib_entry_get_fib_index (fib_entry_index), pfx->fp_proto));
     437       20057 :   mp->mr_route.mr_eos = pfx->fp_eos;
     438       20057 :   mp->mr_route.mr_eos_proto = pfx->fp_payload_proto;
     439       20057 :   mp->mr_route.mr_label = htonl (pfx->fp_label);
     440             : 
     441       20057 :   mp->mr_route.mr_n_paths = path_count;
     442       20057 :   fp = mp->mr_route.mr_paths;
     443       40117 :   vec_foreach (rpath, rpaths)
     444             :   {
     445       20060 :     fib_api_path_encode (rpath, fp);
     446       20060 :     fp++;
     447             :   }
     448             : 
     449       20057 :   vec_free (rpaths);
     450       20057 :   vl_api_send_msg (reg, (u8 *) mp);
     451             : }
     452             : 
     453             : typedef struct vl_api_mpls_route_dump_table_walk_ctx_t_
     454             : {
     455             :   fib_node_index_t *lfeis;
     456             : } vl_api_mpls_route_dump_table_walk_ctx_t;
     457             : 
     458             : static fib_table_walk_rc_t
     459       20057 : vl_api_mpls_route_dump_table_walk (fib_node_index_t fei, void *arg)
     460             : {
     461       20057 :   vl_api_mpls_route_dump_table_walk_ctx_t *ctx = arg;
     462             : 
     463       20057 :   vec_add1 (ctx->lfeis, fei);
     464             : 
     465       20057 :   return (FIB_TABLE_WALK_CONTINUE);
     466             : }
     467             : 
     468             : static void
     469         335 : vl_api_mpls_route_dump_t_handler (vl_api_mpls_route_dump_t * mp)
     470             : {
     471         335 :   vpe_api_main_t *am = &vpe_api_main;
     472             :   vl_api_registration_t *reg;
     473         335 :   fib_node_index_t *lfeip = NULL;
     474         335 :   vl_api_mpls_route_dump_table_walk_ctx_t ctx = {
     475             :     .lfeis = NULL,
     476             :   };
     477             :   u32 fib_index;
     478             : 
     479         335 :   reg = vl_api_client_index_to_registration (mp->client_index);
     480         335 :   if (!reg)
     481           0 :     return;
     482             : 
     483         335 :   fib_index = fib_table_find (FIB_PROTOCOL_MPLS,
     484             :                               ntohl (mp->table.mt_table_id));
     485             : 
     486         335 :   if (INDEX_INVALID != fib_index)
     487             :     {
     488         335 :       fib_table_walk (fib_index,
     489             :                       FIB_PROTOCOL_MPLS,
     490             :                       vl_api_mpls_route_dump_table_walk, &ctx);
     491         335 :       vec_sort_with_function (ctx.lfeis, fib_entry_cmp_for_sort);
     492             : 
     493       20392 :       vec_foreach (lfeip, ctx.lfeis)
     494             :       {
     495       20057 :         send_mpls_route_details (am, reg, mp->context, *lfeip);
     496             :       }
     497             : 
     498         335 :       vec_free (ctx.lfeis);
     499             :     }
     500             : }
     501             : 
     502             : #include <vnet/mpls/mpls.api.c>
     503             : static clib_error_t *
     504         559 : mpls_api_hookup (vlib_main_t * vm)
     505             : {
     506         559 :   api_main_t *am = vlibapi_get_main ();
     507             : 
     508             :   /*
     509             :    * Trace space for 8 MPLS encap labels
     510             :    */
     511         559 :   vl_api_increase_msg_trace_size (am, VL_API_MPLS_TUNNEL_ADD_DEL,
     512             :                                   8 * sizeof (u32));
     513             : 
     514             :   /*
     515             :    * Set up the (msg_name, crc, message-id) table
     516             :    */
     517         559 :   REPLY_MSG_ID_BASE = setup_message_id_table ();
     518             : 
     519         559 :   return 0;
     520             : }
     521             : 
     522       10079 : VLIB_API_INIT_FUNCTION (mpls_api_hookup);
     523             : 
     524             : /*
     525             :  * fd.io coding-style-patch-verification: ON
     526             :  *
     527             :  * Local Variables:
     528             :  * eval: (c-set-style "gnu")
     529             :  * End:
     530             :  */

Generated by: LCOV version 1.14