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