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