6f06e382024b3a065b49bda67879c64105709bb7
[vpp.git] / src / vnet / ip / ip_api.c
1 /*
2  *------------------------------------------------------------------
3  * ip_api.c - vnet ip 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/ethernet/ethernet.h>
26 #include <vnet/ethernet/ethernet_types_api.h>
27 #include <vnet/ip/ip.h>
28 #include <vnet/ip/ip_types_api.h>
29 #include <vnet/ip/ip_punt_drop.h>
30 #include <vnet/ip/ip_types_api.h>
31 #include <vnet/ip/ip_path_mtu.h>
32 #include <vnet/fib/fib_table.h>
33 #include <vnet/fib/fib_api.h>
34 #include <vnet/ethernet/arp_packet.h>
35 #include <vnet/mfib/ip6_mfib.h>
36 #include <vnet/mfib/ip4_mfib.h>
37 #include <vnet/mfib/mfib_signal.h>
38 #include <vnet/mfib/mfib_entry.h>
39 #include <vnet/mfib/mfib_api.h>
40 #include <vnet/ip/ip_source_and_port_range_check.h>
41 #include <vnet/fib/fib_path_list.h>
42 #include <vnet/ip/ip6_hop_by_hop.h>
43 #include <vnet/ip/ip6_link.h>
44 #include <vnet/ip/reass/ip4_sv_reass.h>
45 #include <vnet/ip/reass/ip4_full_reass.h>
46 #include <vnet/ip/reass/ip6_sv_reass.h>
47 #include <vnet/ip/reass/ip6_full_reass.h>
48 #include <vnet/ip/ip_table.h>
49 #include <vnet/ip/ip_container_proxy.h>
50
51 #include <vnet/format_fns.h>
52 #include <vnet/ip/ip.api_enum.h>
53 #include <vnet/ip/ip.api_types.h>
54
55 #define REPLY_MSG_ID_BASE ip4_main.msg_id_base
56 #include <vlibapi/api_helper_macros.h>
57
58 static void
59   vl_api_sw_interface_ip6_enable_disable_t_handler
60   (vl_api_sw_interface_ip6_enable_disable_t * mp)
61 {
62   vl_api_sw_interface_ip6_enable_disable_reply_t *rmp;
63   int rv = 0;
64
65   VALIDATE_SW_IF_INDEX (mp);
66
67   rv = ((mp->enable == 1) ?
68         ip6_link_enable (ntohl (mp->sw_if_index), NULL) :
69         ip6_link_disable (ntohl (mp->sw_if_index)));
70
71   BAD_SW_IF_INDEX_LABEL;
72
73   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
74 }
75
76 static void
77 send_ip_table_details (vpe_api_main_t * am,
78                        vl_api_registration_t * reg,
79                        u32 context, const fib_table_t * table)
80 {
81   vl_api_ip_table_details_t *mp;
82
83   mp = vl_msg_api_alloc (sizeof (*mp));
84   if (!mp)
85     return;
86   clib_memset (mp, 0, sizeof (*mp));
87   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_TABLE_DETAILS);
88   mp->context = context;
89
90   mp->table.is_ip6 = (table->ft_proto == FIB_PROTOCOL_IP6);
91   mp->table.table_id = htonl (table->ft_table_id);
92   memcpy (mp->table.name, table->ft_desc,
93           clib_min (vec_len (table->ft_desc), sizeof (mp->table.name)));
94
95   vl_api_send_msg (reg, (u8 *) mp);
96 }
97
98 static void
99 vl_api_ip_table_dump_t_handler (vl_api_ip_table_dump_t * mp)
100 {
101   vpe_api_main_t *am = &vpe_api_main;
102   vl_api_registration_t *reg;
103   fib_table_t *fib_table;
104
105   reg = vl_api_client_index_to_registration (mp->client_index);
106   if (!reg)
107     return;
108
109   /* *INDENT-OFF* */
110   pool_foreach (fib_table, ip4_main.fibs)
111    {
112     send_ip_table_details(am, reg, mp->context, fib_table);
113   }
114   pool_foreach (fib_table, ip6_main.fibs)
115    {
116     /* don't send link locals */
117     if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
118       continue;
119     send_ip_table_details(am, reg, mp->context, fib_table);
120   }
121   /* *INDENT-ON* */
122 }
123
124 typedef struct vl_api_ip_fib_dump_walk_ctx_t_
125 {
126   fib_node_index_t *feis;
127 } vl_api_ip_fib_dump_walk_ctx_t;
128
129 static fib_table_walk_rc_t
130 vl_api_ip_fib_dump_walk (fib_node_index_t fei, void *arg)
131 {
132   vl_api_ip_fib_dump_walk_ctx_t *ctx = arg;
133
134   vec_add1 (ctx->feis, fei);
135
136   return (FIB_TABLE_WALK_CONTINUE);
137 }
138
139 static void
140 send_ip_route_details (vpe_api_main_t * am,
141                        vl_api_registration_t * reg,
142                        u32 context, fib_node_index_t fib_entry_index)
143 {
144   fib_route_path_t *rpaths, *rpath;
145   vl_api_ip_route_details_t *mp;
146   const fib_prefix_t *pfx;
147   vl_api_fib_path_t *fp;
148   int path_count;
149
150   rpaths = NULL;
151   pfx = fib_entry_get_prefix (fib_entry_index);
152   rpaths = fib_entry_encode (fib_entry_index);
153
154   path_count = vec_len (rpaths);
155   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
156   if (!mp)
157     return;
158   clib_memset (mp, 0, sizeof (*mp));
159   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_ROUTE_DETAILS);
160   mp->context = context;
161
162   ip_prefix_encode (pfx, &mp->route.prefix);
163   mp->route.table_id =
164     htonl (fib_table_get_table_id
165            (fib_entry_get_fib_index (fib_entry_index), pfx->fp_proto));
166   mp->route.n_paths = path_count;
167   mp->route.stats_index =
168     htonl (fib_table_entry_get_stats_index
169            (fib_entry_get_fib_index (fib_entry_index), pfx));
170
171   fp = mp->route.paths;
172   vec_foreach (rpath, rpaths)
173   {
174     fib_api_path_encode (rpath, fp);
175     fp++;
176   }
177
178   vl_api_send_msg (reg, (u8 *) mp);
179   vec_free (rpaths);
180 }
181
182 static void
183 send_ip_route_v2_details (vpe_api_main_t *am, vl_api_registration_t *reg,
184                           u32 context, fib_node_index_t fib_entry_index)
185 {
186   fib_route_path_t *rpaths, *rpath;
187   vl_api_ip_route_v2_details_t *mp;
188   const fib_prefix_t *pfx;
189   vl_api_fib_path_t *fp;
190   int path_count;
191
192   rpaths = NULL;
193   pfx = fib_entry_get_prefix (fib_entry_index);
194   rpaths = fib_entry_encode (fib_entry_index);
195
196   path_count = vec_len (rpaths);
197   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
198   if (!mp)
199     return;
200   clib_memset (mp, 0, sizeof (*mp));
201   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_ROUTE_V2_DETAILS);
202   mp->context = context;
203
204   ip_prefix_encode (pfx, &mp->route.prefix);
205   mp->route.table_id = htonl (fib_table_get_table_id (
206     fib_entry_get_fib_index (fib_entry_index), pfx->fp_proto));
207   mp->route.n_paths = path_count;
208   mp->route.src = fib_entry_get_best_source (fib_entry_index);
209   mp->route.stats_index = htonl (fib_table_entry_get_stats_index (
210     fib_entry_get_fib_index (fib_entry_index), pfx));
211
212   fp = mp->route.paths;
213   vec_foreach (rpath, rpaths)
214     {
215       fib_api_path_encode (rpath, fp);
216       fp++;
217     }
218
219   vl_api_send_msg (reg, (u8 *) mp);
220   vec_free (rpaths);
221 }
222
223 typedef struct apt_ip6_fib_show_ctx_t_
224 {
225   fib_node_index_t *entries;
226 } api_ip6_fib_show_ctx_t;
227
228 static void
229 vl_api_ip_route_dump_t_handler (vl_api_ip_route_dump_t * mp)
230 {
231   vpe_api_main_t *am = &vpe_api_main;
232   fib_node_index_t *fib_entry_index;
233   vl_api_registration_t *reg;
234   fib_protocol_t fproto;
235   u32 fib_index;
236
237   reg = vl_api_client_index_to_registration (mp->client_index);
238   if (!reg)
239     return;
240
241   vl_api_ip_fib_dump_walk_ctx_t ctx = {
242     .feis = NULL,
243   };
244
245   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
246   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
247
248   if (INDEX_INVALID == fib_index)
249     return;
250
251   fib_table_walk (fib_index, fproto, vl_api_ip_fib_dump_walk, &ctx);
252
253   vec_foreach (fib_entry_index, ctx.feis)
254   {
255     send_ip_route_details (am, reg, mp->context, *fib_entry_index);
256   }
257
258   vec_free (ctx.feis);
259 }
260
261 static void
262 vl_api_ip_route_v2_dump_t_handler (vl_api_ip_route_v2_dump_t *mp)
263 {
264   vpe_api_main_t *am = &vpe_api_main;
265   fib_node_index_t *fib_entry_index;
266   vl_api_registration_t *reg;
267   fib_protocol_t fproto;
268   fib_source_t src;
269   u32 fib_index;
270
271   reg = vl_api_client_index_to_registration (mp->client_index);
272   if (!reg)
273     return;
274
275   vl_api_ip_fib_dump_walk_ctx_t ctx = {
276     .feis = NULL,
277   };
278
279   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
280   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
281   src = mp->src;
282
283   if (INDEX_INVALID == fib_index)
284     return;
285
286   if (src)
287     fib_table_walk_w_src (fib_index, fproto, src, vl_api_ip_fib_dump_walk,
288                           &ctx);
289   else
290     fib_table_walk (fib_index, fproto, vl_api_ip_fib_dump_walk, &ctx);
291
292   vec_foreach (fib_entry_index, ctx.feis)
293     {
294       send_ip_route_v2_details (am, reg, mp->context, *fib_entry_index);
295     }
296
297   vec_free (ctx.feis);
298 }
299
300 static void
301 send_ip_mtable_details (vl_api_registration_t * reg,
302                         u32 context, const mfib_table_t * mfib_table)
303 {
304   vl_api_ip_mtable_details_t *mp;
305
306   mp = vl_msg_api_alloc (sizeof (*mp));
307   if (!mp)
308     return;
309   memset (mp, 0, sizeof (*mp));
310   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_MTABLE_DETAILS);
311   mp->context = context;
312
313   mp->table.table_id = htonl (mfib_table->mft_table_id);
314   mp->table.is_ip6 = (FIB_PROTOCOL_IP6 == mfib_table->mft_proto);
315
316   vl_api_send_msg (reg, (u8 *) mp);
317 }
318
319 static void
320 vl_api_ip_mtable_dump_t_handler (vl_api_ip_mtable_dump_t * mp)
321 {
322   vl_api_registration_t *reg;
323   mfib_table_t *mfib_table;
324
325   reg = vl_api_client_index_to_registration (mp->client_index);
326   if (!reg)
327     return;
328
329   /* *INDENT-OFF* */
330   pool_foreach (mfib_table, ip4_main.mfibs)
331    {
332       send_ip_mtable_details (reg, mp->context, mfib_table);
333   }
334   pool_foreach (mfib_table, ip6_main.mfibs)
335    {
336       send_ip_mtable_details (reg, mp->context, mfib_table);
337   }
338   /* *INDENT-ON* */
339 }
340
341 typedef struct vl_api_ip_mfib_dump_ctx_t_
342 {
343   fib_node_index_t *entries;
344 } vl_api_ip_mfib_dump_ctx_t;
345
346 static walk_rc_t
347 mfib_route_dump_walk (fib_node_index_t fei, void *arg)
348 {
349   vl_api_ip_mfib_dump_ctx_t *ctx = arg;
350
351   vec_add1 (ctx->entries, fei);
352
353   return (WALK_CONTINUE);
354 }
355
356 static void
357 send_ip_mroute_details (vpe_api_main_t * am,
358                         vl_api_registration_t * reg,
359                         u32 context, fib_node_index_t mfib_entry_index)
360 {
361   fib_route_path_t *rpaths, *rpath;
362   vl_api_ip_mroute_details_t *mp;
363   const mfib_prefix_t *pfx;
364   vl_api_mfib_path_t *fp;
365   u8 path_count;
366
367   rpaths = NULL;
368   pfx = mfib_entry_get_prefix (mfib_entry_index);
369   rpaths = mfib_entry_encode (mfib_entry_index);
370
371   path_count = vec_len (rpaths);
372   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
373   if (!mp)
374     return;
375   clib_memset (mp, 0, sizeof (*mp));
376   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_MROUTE_DETAILS);
377   mp->context = context;
378
379   ip_mprefix_encode (pfx, &mp->route.prefix);
380   mp->route.table_id =
381     htonl (mfib_table_get_table_id
382            (mfib_entry_get_fib_index (mfib_entry_index), pfx->fp_proto));
383   mp->route.n_paths = path_count;
384   fp = mp->route.paths;
385   vec_foreach (rpath, rpaths)
386   {
387     mfib_api_path_encode (rpath, fp);
388     fp++;
389   }
390
391   vl_api_send_msg (reg, (u8 *) mp);
392   vec_free (rpaths);
393 }
394
395 static void
396 vl_api_ip_mroute_dump_t_handler (vl_api_ip_mroute_dump_t * mp)
397 {
398   vpe_api_main_t *am = &vpe_api_main;
399   vl_api_registration_t *reg;
400   fib_node_index_t *mfeip;
401   fib_protocol_t fproto;
402   u32 fib_index;
403
404   vl_api_ip_mfib_dump_ctx_t ctx = {
405     .entries = NULL,
406   };
407
408   reg = vl_api_client_index_to_registration (mp->client_index);
409   if (!reg)
410     return;
411
412   fproto = fib_ip_proto (mp->table.is_ip6);
413   fib_index = mfib_table_find (fproto, ntohl (mp->table.table_id));
414
415   if (INDEX_INVALID == fib_index)
416     return;
417
418   mfib_table_walk (fib_index, fproto, mfib_route_dump_walk, &ctx);
419
420   vec_sort_with_function (ctx.entries, mfib_entry_cmp_for_sort);
421
422   vec_foreach (mfeip, ctx.entries)
423   {
424     send_ip_mroute_details (am, reg, mp->context, *mfeip);
425   }
426
427   vec_free (ctx.entries);
428 }
429
430 static void
431 vl_api_ip_punt_police_t_handler (vl_api_ip_punt_police_t * mp,
432                                  vlib_main_t * vm)
433 {
434   vl_api_ip_punt_police_reply_t *rmp;
435   int rv = 0;
436
437   if (mp->is_ip6)
438     ip6_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
439   else
440     ip4_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
441
442   REPLY_MACRO (VL_API_IP_PUNT_POLICE_REPLY);
443 }
444
445 static void
446 vl_api_ip_punt_redirect_t_handler (vl_api_ip_punt_redirect_t * mp,
447                                    vlib_main_t * vm)
448 {
449   vl_api_ip_punt_redirect_reply_t *rmp;
450   int rv = 0;
451   ip46_type_t ipv;
452   ip46_address_t nh;
453
454   if (!vnet_sw_if_index_is_api_valid (ntohl (mp->punt.tx_sw_if_index)))
455     goto bad_sw_if_index;
456
457   ipv = ip_address_decode (&mp->punt.nh, &nh);
458   if (mp->is_add)
459     {
460       if (ipv == IP46_TYPE_IP6)
461         {
462           ip6_punt_redirect_add (ntohl (mp->punt.rx_sw_if_index),
463                                  ntohl (mp->punt.tx_sw_if_index), &nh);
464         }
465       else if (ipv == IP46_TYPE_IP4)
466         {
467           ip4_punt_redirect_add (ntohl (mp->punt.rx_sw_if_index),
468                                  ntohl (mp->punt.tx_sw_if_index), &nh);
469         }
470     }
471   else
472     {
473       if (ipv == IP46_TYPE_IP6)
474         {
475           ip6_punt_redirect_del (ntohl (mp->punt.rx_sw_if_index));
476         }
477       else if (ipv == IP46_TYPE_IP4)
478         {
479           ip4_punt_redirect_del (ntohl (mp->punt.rx_sw_if_index));
480         }
481     }
482
483   BAD_SW_IF_INDEX_LABEL;
484
485   REPLY_MACRO (VL_API_IP_PUNT_REDIRECT_REPLY);
486 }
487
488 static clib_error_t *
489 call_elf_section_ip_table_callbacks (vnet_main_t * vnm, u32 table_id,
490                                      u32 flags,
491                                      _vnet_ip_table_function_list_elt_t **
492                                      elts)
493 {
494   _vnet_ip_table_function_list_elt_t *elt;
495   vnet_ip_table_function_priority_t prio;
496   clib_error_t *error = 0;
497
498   for (prio = VNET_IP_TABLE_FUNC_PRIORITY_LOW;
499        prio <= VNET_IP_TABLE_FUNC_PRIORITY_HIGH; prio++)
500     {
501       elt = elts[prio];
502
503       while (elt)
504         {
505           error = elt->fp (vnm, table_id, flags);
506           if (error)
507             return error;
508           elt = elt->next_ip_table_function;
509         }
510     }
511   return error;
512 }
513
514 void
515 ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api)
516 {
517   u32 fib_index, mfib_index;
518   vnet_main_t *vnm = vnet_get_main ();
519
520   /*
521    * ignore action on the default table - this is always present
522    * and cannot be added nor deleted from the API
523    */
524   if (0 != table_id)
525     {
526       /*
527        * The API holds only one lock on the table.
528        * i.e. it can be added many times via the API but needs to be
529        * deleted only once.
530        * The FIB index for unicast and multicast is not necessarily the
531        * same, since internal VPP systesm (like LISP and SR) create
532        * their own unicast tables.
533        */
534       fib_index = fib_table_find (fproto, table_id);
535       mfib_index = mfib_table_find (fproto, table_id);
536
537       if ((~0 != fib_index) || (~0 != mfib_index))
538         call_elf_section_ip_table_callbacks (vnm, table_id, 0 /* is_add */ ,
539                                              vnm->ip_table_add_del_functions);
540
541       if (~0 != fib_index)
542         {
543           fib_table_unlock (fib_index, fproto,
544                             (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI));
545         }
546       if (~0 != mfib_index)
547         {
548           mfib_table_unlock (mfib_index, fproto,
549                              (is_api ? MFIB_SOURCE_API : MFIB_SOURCE_CLI));
550         }
551     }
552 }
553
554 void
555 vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
556 {
557   vl_api_ip_table_add_del_reply_t *rmp;
558   fib_protocol_t fproto = (mp->table.is_ip6 ?
559                            FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
560   u32 table_id = ntohl (mp->table.table_id);
561   int rv = 0;
562
563   if (mp->is_add)
564     {
565       ip_table_create (fproto, table_id, 1, mp->table.name);
566     }
567   else
568     {
569       ip_table_delete (fproto, table_id, 1);
570     }
571
572   REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_REPLY);
573 }
574
575 static int
576 ip_route_add_del_t_handler (vl_api_ip_route_add_del_t * mp, u32 * stats_index)
577 {
578   fib_route_path_t *rpaths = NULL, *rpath;
579   fib_entry_flag_t entry_flags;
580   vl_api_fib_path_t *apath;
581   fib_prefix_t pfx;
582   u32 fib_index;
583   int rv, ii;
584
585   entry_flags = FIB_ENTRY_FLAG_NONE;
586   ip_prefix_decode (&mp->route.prefix, &pfx);
587
588   rv = fib_api_table_id_decode (pfx.fp_proto,
589                                 ntohl (mp->route.table_id), &fib_index);
590   if (0 != rv)
591     goto out;
592
593   if (0 != mp->route.n_paths)
594     vec_validate (rpaths, mp->route.n_paths - 1);
595
596   for (ii = 0; ii < mp->route.n_paths; ii++)
597     {
598       apath = &mp->route.paths[ii];
599       rpath = &rpaths[ii];
600
601       rv = fib_api_path_decode (apath, rpath);
602
603       if ((rpath->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
604           (~0 == rpath->frp_sw_if_index))
605         entry_flags |= (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL);
606
607       if (0 != rv)
608         goto out;
609     }
610
611   rv = fib_api_route_add_del (mp->is_add, mp->is_multipath, fib_index, &pfx,
612                               FIB_SOURCE_API, entry_flags, rpaths);
613
614   if (mp->is_add && 0 == rv)
615     *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
616
617 out:
618   vec_free (rpaths);
619
620   return (rv);
621 }
622
623 static int
624 ip_route_add_del_v2_t_handler (vl_api_ip_route_add_del_v2_t *mp,
625                                u32 *stats_index)
626 {
627   fib_route_path_t *rpaths = NULL, *rpath;
628   fib_entry_flag_t entry_flags;
629   vl_api_fib_path_t *apath;
630   fib_source_t src;
631   fib_prefix_t pfx;
632   u32 fib_index;
633   int rv, ii;
634
635   entry_flags = FIB_ENTRY_FLAG_NONE;
636   ip_prefix_decode (&mp->route.prefix, &pfx);
637
638   rv = fib_api_table_id_decode (pfx.fp_proto, ntohl (mp->route.table_id),
639                                 &fib_index);
640   if (0 != rv)
641     goto out;
642
643   if (0 != mp->route.n_paths)
644     vec_validate (rpaths, mp->route.n_paths - 1);
645
646   for (ii = 0; ii < mp->route.n_paths; ii++)
647     {
648       apath = &mp->route.paths[ii];
649       rpath = &rpaths[ii];
650
651       rv = fib_api_path_decode (apath, rpath);
652
653       if ((rpath->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
654           (~0 == rpath->frp_sw_if_index))
655         entry_flags |= (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL);
656
657       if (0 != rv)
658         goto out;
659     }
660
661   src = (0 == mp->route.src ? FIB_SOURCE_API : mp->route.src);
662
663   rv = fib_api_route_add_del (mp->is_add, mp->is_multipath, fib_index, &pfx,
664                               src, entry_flags, rpaths);
665
666   if (mp->is_add && 0 == rv)
667     *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
668
669 out:
670   vec_free (rpaths);
671
672   return (rv);
673 }
674
675 void
676 vl_api_ip_route_add_del_t_handler (vl_api_ip_route_add_del_t * mp)
677 {
678   vl_api_ip_route_add_del_reply_t *rmp;
679   u32 stats_index = ~0;
680   int rv;
681
682   rv = ip_route_add_del_t_handler (mp, &stats_index);
683
684   /* *INDENT-OFF* */
685   REPLY_MACRO2 (VL_API_IP_ROUTE_ADD_DEL_REPLY,
686   ({
687     rmp->stats_index = htonl (stats_index);
688   }))
689   /* *INDENT-ON* */
690 }
691
692 void
693 vl_api_ip_route_add_del_v2_t_handler (vl_api_ip_route_add_del_v2_t *mp)
694 {
695   vl_api_ip_route_add_del_v2_reply_t *rmp;
696   u32 stats_index = ~0;
697   int rv;
698
699   rv = ip_route_add_del_v2_t_handler (mp, &stats_index);
700
701   /* clang-format off */
702   REPLY_MACRO2 (VL_API_IP_ROUTE_ADD_DEL_V2_REPLY,
703   ({
704     rmp->stats_index = htonl (stats_index);
705   }))
706   /* clang-format on */
707 }
708
709 void
710 vl_api_ip_route_lookup_t_handler (vl_api_ip_route_lookup_t * mp)
711 {
712   vl_api_ip_route_lookup_reply_t *rmp = NULL;
713   fib_route_path_t *rpaths = NULL, *rpath;
714   const fib_prefix_t *pfx = NULL;
715   fib_prefix_t lookup;
716   vl_api_fib_path_t *fp;
717   fib_node_index_t fib_entry_index;
718   u32 fib_index;
719   int npaths = 0;
720   int rv;
721
722   ip_prefix_decode (&mp->prefix, &lookup);
723   rv = fib_api_table_id_decode (lookup.fp_proto, ntohl (mp->table_id),
724                                 &fib_index);
725   if (PREDICT_TRUE (!rv))
726     {
727       if (mp->exact)
728         fib_entry_index = fib_table_lookup_exact_match (fib_index, &lookup);
729       else
730         fib_entry_index = fib_table_lookup (fib_index, &lookup);
731       if (fib_entry_index == FIB_NODE_INDEX_INVALID)
732         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
733       else
734         {
735           pfx = fib_entry_get_prefix (fib_entry_index);
736           rpaths = fib_entry_encode (fib_entry_index);
737           npaths = vec_len (rpaths);
738         }
739     }
740
741   /* *INDENT-OFF* */
742   REPLY_MACRO3_ZERO(VL_API_IP_ROUTE_LOOKUP_REPLY,
743                     npaths * sizeof (*fp),
744   ({
745     if (!rv)
746       {
747         ip_prefix_encode (pfx, &rmp->route.prefix);
748         rmp->route.table_id = mp->table_id;
749         rmp->route.n_paths = npaths;
750         rmp->route.stats_index = fib_table_entry_get_stats_index (fib_index, pfx);
751         rmp->route.stats_index = htonl (rmp->route.stats_index);
752
753         fp = rmp->route.paths;
754         vec_foreach (rpath, rpaths)
755           {
756             fib_api_path_encode (rpath, fp);
757             fp++;
758           }
759       }
760   }));
761   /* *INDENT-ON* */
762   vec_free (rpaths);
763 }
764
765 void
766 vl_api_ip_route_lookup_v2_t_handler (vl_api_ip_route_lookup_v2_t *mp)
767 {
768   vl_api_ip_route_lookup_v2_reply_t *rmp = NULL;
769   fib_route_path_t *rpaths = NULL, *rpath;
770   const fib_prefix_t *pfx = NULL;
771   fib_prefix_t lookup;
772   vl_api_fib_path_t *fp;
773   fib_node_index_t fib_entry_index;
774   u32 fib_index;
775   int npaths = 0;
776   fib_source_t src = 0;
777   int rv;
778
779   ip_prefix_decode (&mp->prefix, &lookup);
780   rv = fib_api_table_id_decode (lookup.fp_proto, ntohl (mp->table_id),
781                                 &fib_index);
782   if (PREDICT_TRUE (!rv))
783     {
784       if (mp->exact)
785         fib_entry_index = fib_table_lookup_exact_match (fib_index, &lookup);
786       else
787         fib_entry_index = fib_table_lookup (fib_index, &lookup);
788       if (fib_entry_index == FIB_NODE_INDEX_INVALID)
789         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
790       else
791         {
792           pfx = fib_entry_get_prefix (fib_entry_index);
793           rpaths = fib_entry_encode (fib_entry_index);
794           npaths = vec_len (rpaths);
795           src = fib_entry_get_best_source (fib_entry_index);
796         }
797     }
798
799   /* clang-format off */
800   REPLY_MACRO3_ZERO(VL_API_IP_ROUTE_LOOKUP_V2_REPLY,
801                     npaths * sizeof (*fp),
802   ({
803     if (!rv)
804       {
805         ip_prefix_encode (pfx, &rmp->route.prefix);
806         rmp->route.table_id = mp->table_id;
807         rmp->route.n_paths = npaths;
808         rmp->route.src = src;
809         rmp->route.stats_index = fib_table_entry_get_stats_index (fib_index, pfx);
810         rmp->route.stats_index = htonl (rmp->route.stats_index);
811
812         fp = rmp->route.paths;
813         vec_foreach (rpath, rpaths)
814           {
815             fib_api_path_encode (rpath, fp);
816             fp++;
817           }
818       }
819   }));
820   /* clang-format on */
821   vec_free (rpaths);
822 }
823
824 void
825 ip_table_create (fib_protocol_t fproto,
826                  u32 table_id, u8 is_api, const u8 * name)
827 {
828   u32 fib_index, mfib_index;
829   vnet_main_t *vnm = vnet_get_main ();
830
831   /*
832    * ignore action on the default table - this is always present
833    * and cannot be added nor deleted from the API
834    */
835   if (0 != table_id)
836     {
837       /*
838        * The API holds only one lock on the table.
839        * i.e. it can be added many times via the API but needs to be
840        * deleted only once.
841        * The FIB index for unicast and multicast is not necessarily the
842        * same, since internal VPP systesm (like LISP and SR) create
843        * their own unicast tables.
844        */
845       fib_index = fib_table_find (fproto, table_id);
846       mfib_index = mfib_table_find (fproto, table_id);
847
848       if (~0 == fib_index)
849         {
850           fib_table_find_or_create_and_lock_w_name (fproto, table_id,
851                                                     (is_api ?
852                                                      FIB_SOURCE_API :
853                                                      FIB_SOURCE_CLI), name);
854         }
855       if (~0 == mfib_index)
856         {
857           mfib_table_find_or_create_and_lock_w_name (fproto, table_id,
858                                                      (is_api ?
859                                                       MFIB_SOURCE_API :
860                                                       MFIB_SOURCE_CLI), name);
861         }
862
863       if ((~0 == fib_index) || (~0 == mfib_index))
864         call_elf_section_ip_table_callbacks (vnm, table_id, 1 /* is_add */ ,
865                                              vnm->ip_table_add_del_functions);
866     }
867 }
868
869 static u32
870 mroute_add_del_handler (u8 is_add,
871                         u8 is_multipath,
872                         u32 fib_index,
873                         const mfib_prefix_t * prefix,
874                         u32 entry_flags,
875                         u32 rpf_id, fib_route_path_t * rpaths)
876 {
877   u32 mfib_entry_index = ~0;
878
879   if (0 == vec_len (rpaths))
880     {
881       mfib_entry_index = mfib_table_entry_update (fib_index, prefix,
882                                                   MFIB_SOURCE_API,
883                                                   rpf_id, entry_flags);
884     }
885   else
886     {
887       if (is_add)
888         {
889           mfib_entry_index =
890             mfib_table_entry_paths_update (fib_index, prefix,
891                                            MFIB_SOURCE_API, rpaths);
892         }
893       else
894         {
895           mfib_table_entry_paths_remove (fib_index, prefix,
896                                          MFIB_SOURCE_API, rpaths);
897         }
898     }
899
900   return (mfib_entry_index);
901 }
902
903 static int
904 api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp,
905                               u32 * stats_index)
906 {
907   fib_route_path_t *rpath, *rpaths = NULL;
908   fib_node_index_t mfib_entry_index;
909   mfib_entry_flags_t eflags;
910   mfib_prefix_t pfx;
911   u32 fib_index;
912   int rv;
913   u16 ii;
914
915   ip_mprefix_decode (&mp->route.prefix, &pfx);
916
917   rv = mfib_api_table_id_decode (pfx.fp_proto,
918                                  ntohl (mp->route.table_id), &fib_index);
919   if (0 != rv)
920     goto out;
921
922   vec_validate (rpaths, mp->route.n_paths - 1);
923
924   for (ii = 0; ii < mp->route.n_paths; ii++)
925     {
926       rpath = &rpaths[ii];
927
928       rv = mfib_api_path_decode (&mp->route.paths[ii], rpath);
929
930       if (0 != rv)
931         goto out;
932     }
933
934   eflags = mfib_api_path_entry_flags_decode (mp->route.entry_flags);
935   mfib_entry_index = mroute_add_del_handler (mp->is_add,
936                                              mp->is_add,
937                                              fib_index, &pfx,
938                                              eflags,
939                                              ntohl (mp->route.rpf_id),
940                                              rpaths);
941
942   if (~0 != mfib_entry_index)
943     *stats_index = mfib_entry_get_stats_index (mfib_entry_index);
944
945 out:
946   return (rv);
947 }
948
949 void
950 vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
951 {
952   vl_api_ip_mroute_add_del_reply_t *rmp;
953   u32 stats_index = ~0;
954   int rv;
955
956   rv = api_mroute_add_del_t_handler (mp, &stats_index);
957
958   /* *INDENT-OFF* */
959   REPLY_MACRO2 (VL_API_IP_MROUTE_ADD_DEL_REPLY,
960   ({
961     rmp->stats_index = htonl (stats_index);
962   }));
963   /* *INDENT-ON* */
964 }
965
966 static void
967 send_ip_details (vpe_api_main_t * am,
968                  vl_api_registration_t * reg, u32 sw_if_index, u8 is_ipv6,
969                  u32 context)
970 {
971   vl_api_ip_details_t *mp;
972
973   mp = vl_msg_api_alloc (sizeof (*mp));
974   clib_memset (mp, 0, sizeof (*mp));
975   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_DETAILS);
976
977   mp->sw_if_index = ntohl (sw_if_index);
978   mp->is_ipv6 = is_ipv6;
979   mp->context = context;
980
981   vl_api_send_msg (reg, (u8 *) mp);
982 }
983
984 static void
985 send_ip_address_details (vpe_api_main_t * am,
986                          vl_api_registration_t * reg,
987                          const fib_prefix_t * pfx,
988                          u32 sw_if_index, u32 context)
989 {
990   vl_api_ip_address_details_t *mp;
991
992   mp = vl_msg_api_alloc (sizeof (*mp));
993   clib_memset (mp, 0, sizeof (*mp));
994   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_ADDRESS_DETAILS);
995
996   ip_prefix_encode (pfx, &mp->prefix);
997   mp->context = context;
998   mp->sw_if_index = htonl (sw_if_index);
999
1000   vl_api_send_msg (reg, (u8 *) mp);
1001 }
1002
1003 static void
1004 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
1005 {
1006   vpe_api_main_t *am = &vpe_api_main;
1007   vl_api_registration_t *reg;
1008   ip6_main_t *im6 = &ip6_main;
1009   ip4_main_t *im4 = &ip4_main;
1010   ip_lookup_main_t *lm6 = &im6->lookup_main;
1011   ip_lookup_main_t *lm4 = &im4->lookup_main;
1012   ip_interface_address_t *ia = 0;
1013   u32 sw_if_index = ~0;
1014   int rv __attribute__ ((unused)) = 0;
1015
1016   VALIDATE_SW_IF_INDEX (mp);
1017
1018   sw_if_index = ntohl (mp->sw_if_index);
1019
1020   reg = vl_api_client_index_to_registration (mp->client_index);
1021   if (!reg)
1022     return;
1023
1024   if (mp->is_ipv6)
1025     {
1026       /* *INDENT-OFF* */
1027       /* Do not send subnet details of the IP-interface for
1028        * unnumbered interfaces. otherwise listening clients
1029        * will be confused that the subnet is applied on more
1030        * than one interface */
1031       foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
1032       ({
1033         fib_prefix_t pfx = {
1034           .fp_addr.ip6 = *(ip6_address_t *)ip_interface_address_get_address (lm6, ia),
1035           .fp_len = ia->address_length,
1036           .fp_proto = FIB_PROTOCOL_IP6,
1037         };
1038         send_ip_address_details(am, reg, &pfx, sw_if_index, mp->context);
1039       }));
1040       /* *INDENT-ON* */
1041     }
1042   else
1043     {
1044       /* *INDENT-OFF* */
1045       foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1046       ({
1047         fib_prefix_t pfx = {
1048           .fp_addr.ip4 = *(ip4_address_t *)ip_interface_address_get_address (lm4, ia),
1049           .fp_len = ia->address_length,
1050           .fp_proto = FIB_PROTOCOL_IP4,
1051         };
1052
1053         send_ip_address_details(am, reg, &pfx, sw_if_index, mp->context);
1054       }));
1055       /* *INDENT-ON* */
1056     }
1057
1058   BAD_SW_IF_INDEX_LABEL;
1059 }
1060
1061 static void
1062 send_ip_unnumbered_details (vpe_api_main_t * am,
1063                             vl_api_registration_t * reg,
1064                             u32 sw_if_index, u32 ip_sw_if_index, u32 context)
1065 {
1066   vl_api_ip_unnumbered_details_t *mp;
1067
1068   mp = vl_msg_api_alloc (sizeof (*mp));
1069   clib_memset (mp, 0, sizeof (*mp));
1070   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_UNNUMBERED_DETAILS);
1071
1072   mp->context = context;
1073   mp->sw_if_index = htonl (sw_if_index);
1074   mp->ip_sw_if_index = htonl (ip_sw_if_index);
1075
1076   vl_api_send_msg (reg, (u8 *) mp);
1077 }
1078
1079 static void
1080 vl_api_ip_unnumbered_dump_t_handler (vl_api_ip_unnumbered_dump_t * mp)
1081 {
1082   vnet_main_t *vnm = vnet_get_main ();
1083   vnet_interface_main_t *im = &vnm->interface_main;
1084   int rv __attribute__ ((unused)) = 0;
1085   vpe_api_main_t *am = &vpe_api_main;
1086   vl_api_registration_t *reg;
1087   vnet_sw_interface_t *si;
1088   u32 sw_if_index;
1089
1090   sw_if_index = ntohl (mp->sw_if_index);
1091
1092   reg = vl_api_client_index_to_registration (mp->client_index);
1093   if (!reg)
1094     return;
1095
1096   if (~0 != sw_if_index)
1097     {
1098       VALIDATE_SW_IF_INDEX (mp);
1099
1100       si = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
1101
1102       if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
1103         {
1104           send_ip_unnumbered_details (am, reg,
1105                                       sw_if_index,
1106                                       si->unnumbered_sw_if_index,
1107                                       mp->context);
1108         }
1109     }
1110   else
1111     {
1112       /* *INDENT-OFF* */
1113       pool_foreach (si, im->sw_interfaces)
1114        {
1115         if ((si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1116           {
1117             send_ip_unnumbered_details(am, reg,
1118                                        si->sw_if_index,
1119                                        si->unnumbered_sw_if_index,
1120                                        mp->context);
1121           }
1122       }
1123       /* *INDENT-ON* */
1124     }
1125
1126   BAD_SW_IF_INDEX_LABEL;
1127 }
1128
1129 static void
1130 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
1131 {
1132   vpe_api_main_t *am = &vpe_api_main;
1133   vnet_main_t *vnm = vnet_get_main ();
1134   //vlib_main_t *vm = vlib_get_main ();
1135   vnet_interface_main_t *im = &vnm->interface_main;
1136   vl_api_registration_t *reg;
1137   vnet_sw_interface_t *si, *sorted_sis;
1138   u32 sw_if_index = ~0;
1139
1140   reg = vl_api_client_index_to_registration (mp->client_index);
1141   if (!reg)
1142     return;
1143
1144   /* Gather interfaces. */
1145   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1146   _vec_len (sorted_sis) = 0;
1147   /* *INDENT-OFF* */
1148   pool_foreach (si, im->sw_interfaces)
1149    {
1150     vec_add1 (sorted_sis, si[0]);
1151   }
1152   /* *INDENT-ON* */
1153
1154   vec_foreach (si, sorted_sis)
1155   {
1156     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1157       {
1158         /* if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index)) */
1159         /*   { */
1160         /*     continue; */
1161         /*   } */
1162         sw_if_index = si->sw_if_index;
1163         send_ip_details (am, reg, sw_if_index, mp->is_ipv6, mp->context);
1164       }
1165   }
1166
1167   vec_free (sorted_sis);
1168 }
1169
1170 static void
1171 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t *mp)
1172 {
1173   vl_api_set_ip_flow_hash_reply_t *rmp;
1174   int rv;
1175   u32 table_id;
1176   flow_hash_config_t flow_hash_config = 0;
1177
1178   table_id = ntohl (mp->vrf_id);
1179
1180 #define _(a,b) if (mp->a) flow_hash_config |= b;
1181   foreach_flow_hash_bit_v1;
1182 #undef _
1183
1184   rv = ip_flow_hash_set ((mp->is_ipv6 ? AF_IP6 : AF_IP4), table_id,
1185                          flow_hash_config);
1186
1187   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1188 }
1189
1190 static void
1191 vl_api_set_ip_flow_hash_v2_t_handler (vl_api_set_ip_flow_hash_v2_t *mp)
1192 {
1193   vl_api_set_ip_flow_hash_v2_reply_t *rmp;
1194   ip_address_family_t af;
1195   int rv;
1196
1197   rv = ip_address_family_decode (mp->af, &af);
1198
1199   if (!rv)
1200     rv = ip_flow_hash_set (af, htonl (mp->table_id),
1201                            htonl (mp->flow_hash_config));
1202
1203   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_V2_REPLY);
1204 }
1205
1206 static void
1207 vl_api_set_ip_flow_hash_router_id_t_handler (
1208   vl_api_set_ip_flow_hash_router_id_t *mp)
1209 {
1210   vl_api_set_ip_flow_hash_router_id_reply_t *rmp;
1211   int rv = 0;
1212
1213   ip_flow_hash_router_id_set (ntohl (mp->router_id));
1214
1215   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_ROUTER_ID_REPLY);
1216 }
1217
1218 void
1219 vl_mfib_signal_send_one (vl_api_registration_t * reg,
1220                          u32 context, const mfib_signal_t * mfs)
1221 {
1222   vl_api_mfib_signal_details_t *mp;
1223   const mfib_prefix_t *prefix;
1224   mfib_table_t *mfib;
1225   mfib_itf_t *mfi;
1226
1227   mp = vl_msg_api_alloc (sizeof (*mp));
1228
1229   clib_memset (mp, 0, sizeof (*mp));
1230   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MFIB_SIGNAL_DETAILS);
1231   mp->context = context;
1232
1233   mfi = mfib_itf_get (mfs->mfs_itf);
1234   prefix = mfib_entry_get_prefix (mfs->mfs_entry);
1235   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1236                          prefix->fp_proto);
1237   mp->table_id = ntohl (mfib->mft_table_id);
1238   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1239
1240   ip_mprefix_encode (prefix, &mp->prefix);
1241
1242   if (0 != mfs->mfs_buffer_len)
1243     {
1244       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1245
1246       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1247     }
1248   else
1249     {
1250       mp->ip_packet_len = 0;
1251     }
1252
1253   vl_api_send_msg (reg, (u8 *) mp);
1254 }
1255
1256 static void
1257 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1258 {
1259   vl_api_registration_t *reg;
1260
1261   reg = vl_api_client_index_to_registration (mp->client_index);
1262   if (!reg)
1263     return;
1264
1265   while (vl_api_can_send_msg (reg) && mfib_signal_send_one (reg, mp->context))
1266     ;
1267 }
1268
1269 static void
1270   vl_api_ip_container_proxy_add_del_t_handler
1271   (vl_api_ip_container_proxy_add_del_t * mp)
1272 {
1273   vl_api_ip_container_proxy_add_del_reply_t *rmp;
1274   vnet_ip_container_proxy_args_t args;
1275   int rv = 0;
1276   clib_error_t *error;
1277
1278   clib_memset (&args, 0, sizeof (args));
1279
1280   ip_prefix_decode (&mp->pfx, &args.prefix);
1281
1282   args.sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
1283   args.is_add = mp->is_add;
1284   if ((error = vnet_ip_container_proxy_add_del (&args)))
1285     {
1286       rv = clib_error_get_code (error);
1287       clib_error_report (error);
1288     }
1289
1290   REPLY_MACRO (VL_API_IP_CONTAINER_PROXY_ADD_DEL_REPLY);
1291 }
1292
1293 typedef struct ip_walk_ctx_t_
1294 {
1295   vl_api_registration_t *reg;
1296   u32 context;
1297 } ip_walk_ctx_t;
1298
1299 static int
1300 ip_container_proxy_send_details (const fib_prefix_t * pfx, u32 sw_if_index,
1301                                  void *args)
1302 {
1303   vl_api_ip_container_proxy_details_t *mp;
1304   ip_walk_ctx_t *ctx = args;
1305
1306   mp = vl_msg_api_alloc (sizeof (*mp));
1307   if (!mp)
1308     return 1;
1309
1310   clib_memset (mp, 0, sizeof (*mp));
1311   mp->_vl_msg_id =
1312     ntohs (REPLY_MSG_ID_BASE + VL_API_IP_CONTAINER_PROXY_DETAILS);
1313   mp->context = ctx->context;
1314
1315   mp->sw_if_index = ntohl (sw_if_index);
1316   ip_prefix_encode (pfx, &mp->prefix);
1317
1318   vl_api_send_msg (ctx->reg, (u8 *) mp);
1319
1320   return 1;
1321 }
1322
1323 static void
1324 vl_api_ip_container_proxy_dump_t_handler (vl_api_ip_container_proxy_dump_t *
1325                                           mp)
1326 {
1327   vl_api_registration_t *reg;
1328
1329   reg = vl_api_client_index_to_registration (mp->client_index);
1330   if (!reg)
1331     return;
1332
1333   ip_walk_ctx_t ctx = {
1334     .context = mp->context,
1335     .reg = reg,
1336   };
1337
1338   ip_container_proxy_walk (ip_container_proxy_send_details, &ctx);
1339 }
1340
1341 static void
1342 vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
1343 {
1344   int rv = 0;
1345   vl_api_ioam_enable_reply_t *rmp;
1346   clib_error_t *error;
1347
1348   /* Ignoring the profile id as currently a single profile
1349    * is supported */
1350   error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable,
1351                            mp->seqno, mp->analyse);
1352   if (error)
1353     {
1354       clib_error_report (error);
1355       rv = clib_error_get_code (error);
1356     }
1357
1358   REPLY_MACRO (VL_API_IOAM_ENABLE_REPLY);
1359 }
1360
1361 static void
1362 vl_api_ioam_disable_t_handler (vl_api_ioam_disable_t * mp)
1363 {
1364   int rv = 0;
1365   vl_api_ioam_disable_reply_t *rmp;
1366   clib_error_t *error;
1367
1368   error = clear_ioam_rewrite_fn ();
1369   if (error)
1370     {
1371       clib_error_report (error);
1372       rv = clib_error_get_code (error);
1373     }
1374
1375   REPLY_MACRO (VL_API_IOAM_DISABLE_REPLY);
1376 }
1377
1378 static void
1379   vl_api_ip_source_and_port_range_check_add_del_t_handler
1380   (vl_api_ip_source_and_port_range_check_add_del_t * mp)
1381 {
1382   vl_api_ip_source_and_port_range_check_add_del_reply_t *rmp;
1383   int rv = 0;
1384
1385   u8 is_add = mp->is_add;
1386   fib_prefix_t pfx;
1387   u16 *low_ports = 0;
1388   u16 *high_ports = 0;
1389   u32 vrf_id;
1390   u16 tmp_low, tmp_high;
1391   u8 num_ranges;
1392   int i;
1393
1394   ip_prefix_decode (&mp->prefix, &pfx);
1395
1396   // Validate port range
1397   num_ranges = mp->number_of_ranges;
1398   if (num_ranges > 32)
1399     {                           // This is size of array in VPE.API
1400       rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
1401       goto reply;
1402     }
1403
1404   vec_reset_length (low_ports);
1405   vec_reset_length (high_ports);
1406
1407   for (i = 0; i < num_ranges; i++)
1408     {
1409       tmp_low = mp->low_ports[i];
1410       tmp_high = mp->high_ports[i];
1411       // If tmp_low <= tmp_high then only need to check tmp_low = 0
1412       // If tmp_low <= tmp_high then only need to check tmp_high > 65535
1413       if (tmp_low > tmp_high || tmp_low == 0 || tmp_high > 65535)
1414         {
1415           rv = VNET_API_ERROR_INVALID_VALUE;
1416           goto reply;
1417         }
1418       vec_add1 (low_ports, tmp_low);
1419       vec_add1 (high_ports, tmp_high + 1);
1420     }
1421
1422   vrf_id = ntohl (mp->vrf_id);
1423
1424   if (vrf_id < 1)
1425     {
1426       rv = VNET_API_ERROR_INVALID_VALUE;
1427       goto reply;
1428     }
1429
1430
1431   if (FIB_PROTOCOL_IP6 == pfx.fp_proto)
1432     {
1433       rv = ip6_source_and_port_range_check_add_del (&pfx.fp_addr.ip6,
1434                                                     pfx.fp_len,
1435                                                     vrf_id,
1436                                                     low_ports,
1437                                                     high_ports, is_add);
1438     }
1439   else
1440     {
1441       rv = ip4_source_and_port_range_check_add_del (&pfx.fp_addr.ip4,
1442                                                     pfx.fp_len,
1443                                                     vrf_id,
1444                                                     low_ports,
1445                                                     high_ports, is_add);
1446     }
1447
1448 reply:
1449   vec_free (low_ports);
1450   vec_free (high_ports);
1451   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY);
1452 }
1453
1454 static void
1455   vl_api_ip_source_and_port_range_check_interface_add_del_t_handler
1456   (vl_api_ip_source_and_port_range_check_interface_add_del_t * mp)
1457 {
1458   vlib_main_t *vm = vlib_get_main ();
1459   vl_api_ip_source_and_port_range_check_interface_add_del_reply_t *rmp;
1460   ip4_main_t *im = &ip4_main;
1461   int rv;
1462   u32 sw_if_index;
1463   u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
1464   u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
1465   uword *p = 0;
1466   int i;
1467
1468   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] =
1469     ntohl (mp->tcp_out_vrf_id);
1470   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] =
1471     ntohl (mp->udp_out_vrf_id);
1472   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] =
1473     ntohl (mp->tcp_in_vrf_id);
1474   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] =
1475     ntohl (mp->udp_in_vrf_id);
1476
1477
1478   for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
1479     {
1480       if (vrf_id[i] != 0 && vrf_id[i] != ~0)
1481         {
1482           p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
1483
1484           if (p == 0)
1485             {
1486               rv = VNET_API_ERROR_INVALID_VALUE;
1487               goto reply;
1488             }
1489
1490           fib_index[i] = p[0];
1491         }
1492       else
1493         fib_index[i] = ~0;
1494     }
1495   sw_if_index = ntohl (mp->sw_if_index);
1496
1497   VALIDATE_SW_IF_INDEX (mp);
1498
1499   rv =
1500     set_ip_source_and_port_range_check (vm, fib_index, sw_if_index,
1501                                         mp->is_add);
1502
1503   BAD_SW_IF_INDEX_LABEL;
1504 reply:
1505
1506   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY);
1507 }
1508
1509 static void
1510   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1511   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1512 {
1513   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1514   ip6_address_t ip;
1515   int rv;
1516
1517   VALIDATE_SW_IF_INDEX (mp);
1518
1519   ip6_address_decode (mp->ip, &ip);
1520
1521   rv = ip6_link_set_local_address (ntohl (mp->sw_if_index), &ip);
1522
1523   BAD_SW_IF_INDEX_LABEL;
1524   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1525 }
1526
1527 static void
1528 vl_api_sw_interface_ip6_get_link_local_address_t_handler (
1529   vl_api_sw_interface_ip6_get_link_local_address_t *mp)
1530 {
1531   vl_api_sw_interface_ip6_get_link_local_address_reply_t *rmp;
1532   const ip6_address_t *ip = NULL;
1533   int rv = 0;
1534
1535   VALIDATE_SW_IF_INDEX (mp);
1536
1537   ip = ip6_get_link_local_address (ntohl (mp->sw_if_index));
1538   if (NULL == ip)
1539     rv = VNET_API_ERROR_IP6_NOT_ENABLED;
1540
1541   BAD_SW_IF_INDEX_LABEL;
1542   /* clang-format off */
1543   REPLY_MACRO2 (VL_API_SW_INTERFACE_IP6_GET_LINK_LOCAL_ADDRESS_REPLY,
1544   ({
1545     if (!rv)
1546       ip6_address_encode (ip, rmp->ip);
1547   }))
1548   /* clang-format on */
1549 }
1550
1551 static void
1552 vl_api_ip_table_replace_begin_t_handler (vl_api_ip_table_replace_begin_t * mp)
1553 {
1554   vl_api_ip_table_replace_begin_reply_t *rmp;
1555   fib_protocol_t fproto;
1556   u32 fib_index;
1557   int rv = 0;
1558
1559   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1560   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
1561
1562   if (INDEX_INVALID == fib_index)
1563     rv = VNET_API_ERROR_NO_SUCH_FIB;
1564   else
1565     {
1566       fib_table_mark (fib_index, fproto, FIB_SOURCE_API);
1567       mfib_table_mark (mfib_table_find (fproto, ntohl (mp->table.table_id)),
1568                        fproto, MFIB_SOURCE_API);
1569     }
1570   REPLY_MACRO (VL_API_IP_TABLE_REPLACE_BEGIN_REPLY);
1571 }
1572
1573 static void
1574 vl_api_ip_table_replace_end_t_handler (vl_api_ip_table_replace_end_t * mp)
1575 {
1576   vl_api_ip_table_replace_end_reply_t *rmp;
1577   fib_protocol_t fproto;
1578   u32 fib_index;
1579   int rv = 0;
1580
1581   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1582   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
1583
1584   if (INDEX_INVALID == fib_index)
1585     rv = VNET_API_ERROR_NO_SUCH_FIB;
1586   else
1587     {
1588       fib_table_sweep (fib_index, fproto, FIB_SOURCE_API);
1589       mfib_table_sweep (mfib_table_find
1590                         (fproto, ntohl (mp->table.table_id)), fproto,
1591                         MFIB_SOURCE_API);
1592     }
1593   REPLY_MACRO (VL_API_IP_TABLE_REPLACE_END_REPLY);
1594 }
1595
1596 static void
1597 vl_api_ip_table_flush_t_handler (vl_api_ip_table_flush_t * mp)
1598 {
1599   vl_api_ip_table_flush_reply_t *rmp;
1600   fib_protocol_t fproto;
1601   u32 fib_index;
1602   int rv = 0;
1603
1604   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1605   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
1606
1607   if (INDEX_INVALID == fib_index)
1608     rv = VNET_API_ERROR_NO_SUCH_FIB;
1609   else
1610     {
1611       vnet_main_t *vnm = vnet_get_main ();
1612       vnet_interface_main_t *im = &vnm->interface_main;
1613       vnet_sw_interface_t *si;
1614
1615       /* Shut down interfaces in this FIB / clean out intfc routes */
1616       /* *INDENT-OFF* */
1617       pool_foreach (si, im->sw_interfaces)
1618        {
1619         if (fib_index == fib_table_get_index_for_sw_if_index (fproto,
1620                                                               si->sw_if_index))
1621           {
1622             u32 flags = si->flags;
1623             flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
1624             vnet_sw_interface_set_flags (vnm, si->sw_if_index, flags);
1625           }
1626       }
1627       /* *INDENT-ON* */
1628
1629       fib_table_flush (fib_index, fproto, FIB_SOURCE_API);
1630       mfib_table_flush (mfib_table_find (fproto, ntohl (mp->table.table_id)),
1631                         fproto, MFIB_SOURCE_API);
1632     }
1633
1634   REPLY_MACRO (VL_API_IP_TABLE_FLUSH_REPLY);
1635 }
1636
1637 void
1638 vl_api_ip_reassembly_set_t_handler (vl_api_ip_reassembly_set_t * mp)
1639 {
1640   vl_api_ip_reassembly_set_reply_t *rmp;
1641   int rv = 0;
1642   switch ((vl_api_ip_reass_type_t) clib_net_to_host_u32 (mp->type))
1643     {
1644     case IP_REASS_TYPE_FULL:
1645       if (mp->is_ip6)
1646         {
1647           rv = ip6_full_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1648                                    clib_net_to_host_u32
1649                                    (mp->max_reassemblies),
1650                                    clib_net_to_host_u32
1651                                    (mp->max_reassembly_length),
1652                                    clib_net_to_host_u32
1653                                    (mp->expire_walk_interval_ms));
1654         }
1655       else
1656         {
1657           rv = ip4_full_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1658                                    clib_net_to_host_u32
1659                                    (mp->max_reassemblies),
1660                                    clib_net_to_host_u32
1661                                    (mp->max_reassembly_length),
1662                                    clib_net_to_host_u32
1663                                    (mp->expire_walk_interval_ms));
1664         }
1665       break;
1666     case IP_REASS_TYPE_SHALLOW_VIRTUAL:
1667       if (mp->is_ip6)
1668         {
1669           rv =
1670             ip6_sv_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1671                               clib_net_to_host_u32 (mp->max_reassemblies),
1672                               clib_net_to_host_u32
1673                               (mp->max_reassembly_length),
1674                               clib_net_to_host_u32
1675                               (mp->expire_walk_interval_ms));
1676         }
1677       else
1678         {
1679           rv = ip4_sv_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1680                                  clib_net_to_host_u32 (mp->max_reassemblies),
1681                                  clib_net_to_host_u32
1682                                  (mp->max_reassembly_length),
1683                                  clib_net_to_host_u32
1684                                  (mp->expire_walk_interval_ms));
1685         }
1686       break;
1687     }
1688
1689   REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
1690 }
1691
1692 void
1693 vl_api_ip_reassembly_get_t_handler (vl_api_ip_reassembly_get_t * mp)
1694 {
1695   vl_api_registration_t *rp;
1696
1697   rp = vl_api_client_index_to_registration (mp->client_index);
1698   if (rp == 0)
1699     return;
1700
1701   vl_api_ip_reassembly_get_reply_t *rmp = vl_msg_api_alloc (sizeof (*rmp));
1702   clib_memset (rmp, 0, sizeof (*rmp));
1703   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_REASSEMBLY_GET_REPLY);
1704   rmp->context = mp->context;
1705   rmp->retval = 0;
1706   u32 timeout_ms;
1707   u32 max_reassemblies;
1708   u32 max_reassembly_length;
1709   u32 expire_walk_interval_ms;
1710   switch ((vl_api_ip_reass_type_t) clib_net_to_host_u32 (mp->type))
1711     {
1712     case IP_REASS_TYPE_FULL:
1713       if (mp->is_ip6)
1714         {
1715           rmp->is_ip6 = 1;
1716           ip6_full_reass_get (&timeout_ms, &max_reassemblies,
1717                               &max_reassembly_length,
1718                               &expire_walk_interval_ms);
1719         }
1720       else
1721         {
1722           rmp->is_ip6 = 0;
1723           ip4_full_reass_get (&timeout_ms, &max_reassemblies,
1724                               &max_reassembly_length,
1725                               &expire_walk_interval_ms);
1726         }
1727       break;
1728     case IP_REASS_TYPE_SHALLOW_VIRTUAL:
1729       if (mp->is_ip6)
1730         {
1731           rmp->is_ip6 = 1;
1732           ip6_sv_reass_get (&timeout_ms, &max_reassemblies,
1733                             &max_reassembly_length, &expire_walk_interval_ms);
1734         }
1735       else
1736         {
1737           rmp->is_ip6 = 0;
1738           ip4_sv_reass_get (&timeout_ms, &max_reassemblies,
1739                             &max_reassembly_length, &expire_walk_interval_ms);
1740         }
1741       break;
1742     }
1743   rmp->timeout_ms = clib_host_to_net_u32 (timeout_ms);
1744   rmp->max_reassemblies = clib_host_to_net_u32 (max_reassemblies);
1745   rmp->max_reassembly_length = clib_host_to_net_u32 (max_reassembly_length);
1746   rmp->expire_walk_interval_ms =
1747     clib_host_to_net_u32 (expire_walk_interval_ms);
1748   vl_api_send_msg (rp, (u8 *) rmp);
1749 }
1750
1751 void
1752   vl_api_ip_reassembly_enable_disable_t_handler
1753   (vl_api_ip_reassembly_enable_disable_t * mp)
1754 {
1755   vl_api_ip_reassembly_enable_disable_reply_t *rmp;
1756   int rv = 0;
1757   switch ((vl_api_ip_reass_type_t) clib_net_to_host_u32 (mp->type))
1758     {
1759     case IP_REASS_TYPE_FULL:
1760       rv =
1761         ip4_full_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
1762                                        mp->enable_ip4);
1763       if (0 == rv)
1764         rv =
1765           ip6_full_reass_enable_disable (clib_net_to_host_u32
1766                                          (mp->sw_if_index), mp->enable_ip6);
1767       break;
1768     case IP_REASS_TYPE_SHALLOW_VIRTUAL:
1769       rv =
1770         ip4_sv_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
1771                                      mp->enable_ip4);
1772       if (0 == rv)
1773         {
1774           rv =
1775             ip6_sv_reass_enable_disable (clib_net_to_host_u32
1776                                          (mp->sw_if_index), mp->enable_ip6);
1777         }
1778       break;
1779     }
1780
1781   REPLY_MACRO (VL_API_IP_REASSEMBLY_ENABLE_DISABLE_REPLY);
1782 }
1783
1784 static walk_rc_t
1785 send_ip_punt_redirect_details (u32 rx_sw_if_index,
1786                                const ip_punt_redirect_rx_t * ipr, void *arg)
1787 {
1788   vl_api_ip_punt_redirect_details_t *mp;
1789   fib_path_encode_ctx_t path_ctx = {
1790     .rpaths = NULL,
1791   };
1792   ip_walk_ctx_t *ctx = arg;
1793
1794   mp = vl_msg_api_alloc (sizeof (*mp));
1795   if (!mp)
1796     return (WALK_STOP);;
1797
1798   clib_memset (mp, 0, sizeof (*mp));
1799   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IP_PUNT_REDIRECT_DETAILS);
1800   mp->context = ctx->context;
1801
1802   fib_path_list_walk_w_ext (ipr->pl, NULL, fib_path_encode, &path_ctx);
1803
1804   mp->punt.rx_sw_if_index = htonl (rx_sw_if_index);
1805   mp->punt.tx_sw_if_index = htonl (path_ctx.rpaths[0].frp_sw_if_index);
1806
1807   ip_address_encode (&path_ctx.rpaths[0].frp_addr,
1808                      fib_proto_to_ip46 (ipr->fproto), &mp->punt.nh);
1809
1810   vl_api_send_msg (ctx->reg, (u8 *) mp);
1811
1812   vec_free (path_ctx.rpaths);
1813
1814   return (WALK_CONTINUE);
1815 }
1816
1817 static void
1818 vl_api_ip_punt_redirect_dump_t_handler (vl_api_ip_punt_redirect_dump_t * mp)
1819 {
1820   vl_api_registration_t *reg;
1821   fib_protocol_t fproto = FIB_PROTOCOL_IP4;
1822
1823   reg = vl_api_client_index_to_registration (mp->client_index);
1824   if (!reg)
1825     return;
1826
1827   if (mp->is_ipv6 == 1)
1828     fproto = FIB_PROTOCOL_IP6;
1829
1830   ip_walk_ctx_t ctx = {
1831     .reg = reg,
1832     .context = mp->context,
1833   };
1834
1835   if (~0 != mp->sw_if_index)
1836     {
1837       u32 rx_sw_if_index;
1838       index_t pri;
1839
1840       rx_sw_if_index = ntohl (mp->sw_if_index);
1841       pri = ip_punt_redirect_find (fproto, rx_sw_if_index);
1842
1843       if (INDEX_INVALID == pri)
1844         return;
1845
1846       send_ip_punt_redirect_details (rx_sw_if_index,
1847                                      ip_punt_redirect_get (pri), &ctx);
1848     }
1849   else
1850     ip_punt_redirect_walk (fproto, send_ip_punt_redirect_details, &ctx);
1851 }
1852
1853 void
1854 vl_api_ip_path_mtu_update_t_handler (vl_api_ip_path_mtu_update_t *mp)
1855 {
1856   vl_api_ip_path_mtu_update_reply_t *rmp;
1857   ip_address_t nh;
1858   int rv = 0;
1859
1860   ip_address_decode2 (&mp->pmtu.nh, &nh);
1861
1862   rv = ip_path_mtu_update (&nh, ntohl (mp->pmtu.table_id),
1863                            ntohs (mp->pmtu.path_mtu));
1864
1865   REPLY_MACRO (VL_API_IP_PATH_MTU_UPDATE_REPLY);
1866 }
1867
1868 void
1869 vl_api_ip_path_mtu_replace_begin_t_handler (
1870   vl_api_ip_path_mtu_replace_begin_t *mp)
1871 {
1872   vl_api_ip_path_mtu_replace_begin_reply_t *rmp;
1873   int rv;
1874
1875   rv = ip_path_mtu_replace_begin ();
1876
1877   REPLY_MACRO (VL_API_IP_PATH_MTU_REPLACE_BEGIN_REPLY);
1878 }
1879
1880 void
1881 vl_api_ip_path_mtu_replace_end_t_handler (vl_api_ip_path_mtu_replace_end_t *mp)
1882 {
1883   vl_api_ip_path_mtu_replace_end_reply_t *rmp;
1884   int rv;
1885
1886   rv = ip_path_mtu_replace_end ();
1887
1888   REPLY_MACRO (VL_API_IP_PATH_MTU_REPLACE_END_REPLY);
1889 }
1890
1891 static void
1892 send_ip_path_mtu_details (index_t ipti, vl_api_registration_t *rp, u32 context)
1893 {
1894   vl_api_ip_path_mtu_details_t *rmp;
1895   ip_address_t ip;
1896   ip_pmtu_t *ipt;
1897
1898   ipt = ip_path_mtu_get (ipti);
1899
1900   REPLY_MACRO_DETAILS4 (VL_API_IP_PATH_MTU_DETAILS, rp, context, ({
1901                           ip_pmtu_get_ip (ipt, &ip);
1902                           ip_address_encode2 (&ip, &rmp->pmtu.nh);
1903                           rmp->pmtu.table_id =
1904                             htonl (ip_pmtu_get_table_id (ipt));
1905                           rmp->pmtu.path_mtu = htons (ipt->ipt_cfg_pmtu);
1906                         }));
1907 }
1908
1909 static void
1910 vl_api_ip_path_mtu_get_t_handler (vl_api_ip_path_mtu_get_t *mp)
1911 {
1912   vl_api_ip_path_mtu_get_reply_t *rmp;
1913   i32 rv = 0;
1914
1915   REPLY_AND_DETAILS_MACRO (
1916     VL_API_IP_PATH_MTU_GET_REPLY, ip_pmtu_pool,
1917     ({ send_ip_path_mtu_details (cursor, rp, mp->context); }));
1918 }
1919
1920 #include <vnet/ip/ip.api.c>
1921
1922 static clib_error_t *
1923 ip_api_hookup (vlib_main_t * vm)
1924 {
1925   api_main_t *am = vlibapi_get_main ();
1926
1927   /*
1928    * Mark the route add/del API as MP safe
1929    */
1930   am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL] = 1;
1931   am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL_REPLY] = 1;
1932   am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL_V2] = 1;
1933   am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL_V2_REPLY] = 1;
1934
1935   /*
1936    * Set up the (msg_name, crc, message-id) table
1937    */
1938   REPLY_MSG_ID_BASE = setup_message_id_table ();
1939
1940   return 0;
1941 }
1942
1943 VLIB_API_INIT_FUNCTION (ip_api_hookup);
1944
1945 /*
1946  * fd.io coding-style-patch-verification: ON
1947  *
1948  * Local Variables:
1949  * eval: (c-set-style "gnu")
1950  * End:
1951  */