api: ip: add IP_ROUTE_LOOKUP API
[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/ip4_fib.h>
41 #include <vnet/fib/ip6_fib.h>
42 #include <vnet/fib/fib_path_list.h>
43 #include <vnet/ip/ip6_hop_by_hop.h>
44 #include <vnet/ip/ip6_link.h>
45 #include <vnet/ip/reass/ip4_sv_reass.h>
46 #include <vnet/ip/reass/ip4_full_reass.h>
47 #include <vnet/ip/reass/ip6_sv_reass.h>
48 #include <vnet/ip/reass/ip6_full_reass.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   int 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 = htonl (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 void
456 ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api)
457 {
458   u32 fib_index, mfib_index;
459
460   /*
461    * ignore action on the default table - this is always present
462    * and cannot be added nor deleted from the API
463    */
464   if (0 != table_id)
465     {
466       /*
467        * The API holds only one lock on the table.
468        * i.e. it can be added many times via the API but needs to be
469        * deleted only once.
470        * The FIB index for unicast and multicast is not necessarily the
471        * same, since internal VPP systesm (like LISP and SR) create
472        * their own unicast tables.
473        */
474       fib_index = fib_table_find (fproto, table_id);
475       mfib_index = mfib_table_find (fproto, table_id);
476
477       if (~0 != fib_index)
478         {
479           fib_table_unlock (fib_index, fproto,
480                             (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI));
481         }
482       if (~0 != mfib_index)
483         {
484           mfib_table_unlock (mfib_index, fproto,
485                              (is_api ? MFIB_SOURCE_API : MFIB_SOURCE_CLI));
486         }
487     }
488 }
489
490 void
491 vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
492 {
493   vl_api_ip_table_add_del_reply_t *rmp;
494   fib_protocol_t fproto = (mp->table.is_ip6 ?
495                            FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
496   u32 table_id = ntohl (mp->table.table_id);
497   int rv = 0;
498
499   if (mp->is_add)
500     {
501       ip_table_create (fproto, table_id, 1, mp->table.name);
502     }
503   else
504     {
505       ip_table_delete (fproto, table_id, 1);
506     }
507
508   REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_REPLY);
509 }
510
511 static int
512 ip_route_add_del_t_handler (vl_api_ip_route_add_del_t * mp, u32 * stats_index)
513 {
514   fib_route_path_t *rpaths = NULL, *rpath;
515   fib_entry_flag_t entry_flags;
516   vl_api_fib_path_t *apath;
517   fib_prefix_t pfx;
518   u32 fib_index;
519   int rv, ii;
520
521   entry_flags = FIB_ENTRY_FLAG_NONE;
522   ip_prefix_decode (&mp->route.prefix, &pfx);
523
524   rv = fib_api_table_id_decode (pfx.fp_proto,
525                                 ntohl (mp->route.table_id), &fib_index);
526   if (0 != rv)
527     goto out;
528
529   if (0 != mp->route.n_paths)
530     vec_validate (rpaths, mp->route.n_paths - 1);
531
532   for (ii = 0; ii < mp->route.n_paths; ii++)
533     {
534       apath = &mp->route.paths[ii];
535       rpath = &rpaths[ii];
536
537       rv = fib_api_path_decode (apath, rpath);
538
539       if ((rpath->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
540           (~0 == rpath->frp_sw_if_index))
541         entry_flags |= (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL);
542
543       if (0 != rv)
544         goto out;
545     }
546
547   rv = fib_api_route_add_del (mp->is_add,
548                               mp->is_multipath,
549                               fib_index, &pfx, entry_flags, rpaths);
550
551   if (mp->is_add && 0 == rv)
552     *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
553
554 out:
555   vec_free (rpaths);
556
557   return (rv);
558 }
559
560 void
561 vl_api_ip_route_add_del_t_handler (vl_api_ip_route_add_del_t * mp)
562 {
563   vl_api_ip_route_add_del_reply_t *rmp;
564   u32 stats_index = ~0;
565   int rv;
566
567   rv = ip_route_add_del_t_handler (mp, &stats_index);
568
569   /* *INDENT-OFF* */
570   REPLY_MACRO2 (VL_API_IP_ROUTE_ADD_DEL_REPLY,
571   ({
572     rmp->stats_index = htonl (stats_index);
573   }))
574   /* *INDENT-ON* */
575 }
576
577 void
578 vl_api_ip_route_lookup_t_handler (vl_api_ip_route_lookup_t * mp)
579 {
580   vl_api_ip_route_lookup_reply_t *rmp = NULL;
581   fib_route_path_t *rpaths = NULL, *rpath;
582   const fib_prefix_t *pfx = NULL;
583   fib_prefix_t lookup;
584   vl_api_fib_path_t *fp;
585   fib_node_index_t fib_entry_index;
586   u32 fib_index;
587   int npaths = 0;
588   int rv;
589
590   ip_prefix_decode (&mp->prefix, &lookup);
591   rv = fib_api_table_id_decode (lookup.fp_proto, ntohl (mp->table_id),
592                                 &fib_index);
593   if (PREDICT_TRUE (!rv))
594     {
595       if (mp->exact)
596         fib_entry_index = fib_table_lookup_exact_match (fib_index, &lookup);
597       else
598         fib_entry_index = fib_table_lookup (fib_index, &lookup);
599       if (fib_entry_index == FIB_NODE_INDEX_INVALID)
600         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
601       else
602         {
603           pfx = fib_entry_get_prefix (fib_entry_index);
604           rpaths = fib_entry_encode (fib_entry_index);
605           npaths = vec_len (rpaths);
606         }
607     }
608
609   /* *INDENT-OFF* */
610   REPLY_MACRO3_ZERO(VL_API_IP_ROUTE_LOOKUP_REPLY,
611                     npaths * sizeof (*fp),
612   ({
613     if (!rv)
614       {
615         ip_prefix_encode (pfx, &rmp->route.prefix);
616         rmp->route.table_id = mp->table_id;
617         rmp->route.n_paths = npaths;
618         rmp->route.stats_index = fib_table_entry_get_stats_index (fib_index, pfx);
619         rmp->route.stats_index = htonl (rmp->route.stats_index);
620
621         fp = rmp->route.paths;
622         vec_foreach (rpath, rpaths)
623           {
624             fib_api_path_encode (rpath, fp);
625             fp++;
626           }
627       }
628   }));
629   /* *INDENT-ON* */
630   vec_free (rpaths);
631 }
632
633 void
634 ip_table_create (fib_protocol_t fproto,
635                  u32 table_id, u8 is_api, const u8 * name)
636 {
637   u32 fib_index, mfib_index;
638
639   /*
640    * ignore action on the default table - this is always present
641    * and cannot be added nor deleted from the API
642    */
643   if (0 != table_id)
644     {
645       /*
646        * The API holds only one lock on the table.
647        * i.e. it can be added many times via the API but needs to be
648        * deleted only once.
649        * The FIB index for unicast and multicast is not necessarily the
650        * same, since internal VPP systesm (like LISP and SR) create
651        * their own unicast tables.
652        */
653       fib_index = fib_table_find (fproto, table_id);
654       mfib_index = mfib_table_find (fproto, table_id);
655
656       if (~0 == fib_index)
657         {
658           fib_table_find_or_create_and_lock_w_name (fproto, table_id,
659                                                     (is_api ?
660                                                      FIB_SOURCE_API :
661                                                      FIB_SOURCE_CLI), name);
662         }
663       if (~0 == mfib_index)
664         {
665           mfib_table_find_or_create_and_lock_w_name (fproto, table_id,
666                                                      (is_api ?
667                                                       MFIB_SOURCE_API :
668                                                       MFIB_SOURCE_CLI), name);
669         }
670     }
671 }
672
673 static u32
674 mroute_add_del_handler (u8 is_add,
675                         u8 is_multipath,
676                         u32 fib_index,
677                         const mfib_prefix_t * prefix,
678                         u32 entry_flags,
679                         u32 rpf_id, fib_route_path_t * rpaths)
680 {
681   u32 mfib_entry_index = ~0;
682
683   if (0 == vec_len (rpaths))
684     {
685       mfib_entry_index = mfib_table_entry_update (fib_index, prefix,
686                                                   MFIB_SOURCE_API,
687                                                   rpf_id, entry_flags);
688     }
689   else
690     {
691       if (is_add)
692         {
693           mfib_entry_index =
694             mfib_table_entry_paths_update (fib_index, prefix,
695                                            MFIB_SOURCE_API, rpaths);
696         }
697       else
698         {
699           mfib_table_entry_paths_remove (fib_index, prefix,
700                                          MFIB_SOURCE_API, rpaths);
701         }
702     }
703
704   return (mfib_entry_index);
705 }
706
707 static int
708 api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp,
709                               u32 * stats_index)
710 {
711   fib_route_path_t *rpath, *rpaths = NULL;
712   fib_node_index_t mfib_entry_index;
713   mfib_prefix_t pfx;
714   u32 fib_index;
715   int rv;
716   u16 ii;
717
718   ip_mprefix_decode (&mp->route.prefix, &pfx);
719
720   rv = mfib_api_table_id_decode (pfx.fp_proto,
721                                  ntohl (mp->route.table_id), &fib_index);
722   if (0 != rv)
723     goto out;
724
725   vec_validate (rpaths, mp->route.n_paths - 1);
726
727   for (ii = 0; ii < mp->route.n_paths; ii++)
728     {
729       rpath = &rpaths[ii];
730
731       rv = mfib_api_path_decode (&mp->route.paths[ii], rpath);
732
733       if (0 != rv)
734         goto out;
735     }
736
737   mfib_entry_index = mroute_add_del_handler (mp->is_add,
738                                              mp->is_add,
739                                              fib_index, &pfx,
740                                              ntohl (mp->route.entry_flags),
741                                              ntohl (mp->route.rpf_id),
742                                              rpaths);
743
744   if (~0 != mfib_entry_index)
745     *stats_index = mfib_entry_get_stats_index (mfib_entry_index);
746
747 out:
748   return (rv);
749 }
750
751 void
752 vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
753 {
754   vl_api_ip_mroute_add_del_reply_t *rmp;
755   u32 stats_index = ~0;
756   int rv;
757
758   rv = api_mroute_add_del_t_handler (mp, &stats_index);
759
760   /* *INDENT-OFF* */
761   REPLY_MACRO2 (VL_API_IP_MROUTE_ADD_DEL_REPLY,
762   ({
763     rmp->stats_index = htonl (stats_index);
764   }));
765   /* *INDENT-ON* */
766 }
767
768 static void
769 send_ip_details (vpe_api_main_t * am,
770                  vl_api_registration_t * reg, u32 sw_if_index, u8 is_ipv6,
771                  u32 context)
772 {
773   vl_api_ip_details_t *mp;
774
775   mp = vl_msg_api_alloc (sizeof (*mp));
776   clib_memset (mp, 0, sizeof (*mp));
777   mp->_vl_msg_id = ntohs (VL_API_IP_DETAILS);
778
779   mp->sw_if_index = ntohl (sw_if_index);
780   mp->is_ipv6 = is_ipv6;
781   mp->context = context;
782
783   vl_api_send_msg (reg, (u8 *) mp);
784 }
785
786 static void
787 send_ip_address_details (vpe_api_main_t * am,
788                          vl_api_registration_t * reg,
789                          const fib_prefix_t * pfx,
790                          u32 sw_if_index, u32 context)
791 {
792   vl_api_ip_address_details_t *mp;
793
794   mp = vl_msg_api_alloc (sizeof (*mp));
795   clib_memset (mp, 0, sizeof (*mp));
796   mp->_vl_msg_id = ntohs (VL_API_IP_ADDRESS_DETAILS);
797
798   ip_prefix_encode (pfx, &mp->prefix);
799   mp->context = context;
800   mp->sw_if_index = htonl (sw_if_index);
801
802   vl_api_send_msg (reg, (u8 *) mp);
803 }
804
805 static void
806 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
807 {
808   vpe_api_main_t *am = &vpe_api_main;
809   vl_api_registration_t *reg;
810   ip6_main_t *im6 = &ip6_main;
811   ip4_main_t *im4 = &ip4_main;
812   ip_lookup_main_t *lm6 = &im6->lookup_main;
813   ip_lookup_main_t *lm4 = &im4->lookup_main;
814   ip_interface_address_t *ia = 0;
815   u32 sw_if_index = ~0;
816   int rv __attribute__ ((unused)) = 0;
817
818   VALIDATE_SW_IF_INDEX (mp);
819
820   sw_if_index = ntohl (mp->sw_if_index);
821
822   reg = vl_api_client_index_to_registration (mp->client_index);
823   if (!reg)
824     return;
825
826   if (mp->is_ipv6)
827     {
828       /* *INDENT-OFF* */
829       /* Do not send subnet details of the IP-interface for
830        * unnumbered interfaces. otherwise listening clients
831        * will be confused that the subnet is applied on more
832        * than one interface */
833       foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
834       ({
835         fib_prefix_t pfx = {
836           .fp_addr.ip6 = *(ip6_address_t *)ip_interface_address_get_address (lm6, ia),
837           .fp_len = ia->address_length,
838           .fp_proto = FIB_PROTOCOL_IP6,
839         };
840         send_ip_address_details(am, reg, &pfx, sw_if_index, mp->context);
841       }));
842       /* *INDENT-ON* */
843     }
844   else
845     {
846       /* *INDENT-OFF* */
847       foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
848       ({
849         fib_prefix_t pfx = {
850           .fp_addr.ip4 = *(ip4_address_t *)ip_interface_address_get_address (lm4, ia),
851           .fp_len = ia->address_length,
852           .fp_proto = FIB_PROTOCOL_IP4,
853         };
854
855         send_ip_address_details(am, reg, &pfx, sw_if_index, mp->context);
856       }));
857       /* *INDENT-ON* */
858     }
859
860   BAD_SW_IF_INDEX_LABEL;
861 }
862
863 static void
864 send_ip_unnumbered_details (vpe_api_main_t * am,
865                             vl_api_registration_t * reg,
866                             u32 sw_if_index, u32 ip_sw_if_index, u32 context)
867 {
868   vl_api_ip_unnumbered_details_t *mp;
869
870   mp = vl_msg_api_alloc (sizeof (*mp));
871   clib_memset (mp, 0, sizeof (*mp));
872   mp->_vl_msg_id = ntohs (VL_API_IP_UNNUMBERED_DETAILS);
873
874   mp->context = context;
875   mp->sw_if_index = htonl (sw_if_index);
876   mp->ip_sw_if_index = htonl (ip_sw_if_index);
877
878   vl_api_send_msg (reg, (u8 *) mp);
879 }
880
881 static void
882 vl_api_ip_unnumbered_dump_t_handler (vl_api_ip_unnumbered_dump_t * mp)
883 {
884   vnet_main_t *vnm = vnet_get_main ();
885   vnet_interface_main_t *im = &vnm->interface_main;
886   int rv __attribute__ ((unused)) = 0;
887   vpe_api_main_t *am = &vpe_api_main;
888   vl_api_registration_t *reg;
889   vnet_sw_interface_t *si;
890   u32 sw_if_index;
891
892   sw_if_index = ntohl (mp->sw_if_index);
893
894   reg = vl_api_client_index_to_registration (mp->client_index);
895   if (!reg)
896     return;
897
898   if (~0 != sw_if_index)
899     {
900       VALIDATE_SW_IF_INDEX (mp);
901
902       si = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
903
904       if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
905         {
906           send_ip_unnumbered_details (am, reg,
907                                       sw_if_index,
908                                       si->unnumbered_sw_if_index,
909                                       mp->context);
910         }
911     }
912   else
913     {
914       /* *INDENT-OFF* */
915       pool_foreach (si, im->sw_interfaces,
916       ({
917         if ((si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
918           {
919             send_ip_unnumbered_details(am, reg,
920                                        si->sw_if_index,
921                                        si->unnumbered_sw_if_index,
922                                        mp->context);
923           }
924       }));
925       /* *INDENT-ON* */
926     }
927
928   BAD_SW_IF_INDEX_LABEL;
929 }
930
931 static void
932 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
933 {
934   vpe_api_main_t *am = &vpe_api_main;
935   vnet_main_t *vnm = vnet_get_main ();
936   //vlib_main_t *vm = vlib_get_main ();
937   vnet_interface_main_t *im = &vnm->interface_main;
938   vl_api_registration_t *reg;
939   vnet_sw_interface_t *si, *sorted_sis;
940   u32 sw_if_index = ~0;
941
942   reg = vl_api_client_index_to_registration (mp->client_index);
943   if (!reg)
944     return;
945
946   /* Gather interfaces. */
947   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
948   _vec_len (sorted_sis) = 0;
949   /* *INDENT-OFF* */
950   pool_foreach (si, im->sw_interfaces,
951   ({
952     vec_add1 (sorted_sis, si[0]);
953   }));
954   /* *INDENT-ON* */
955
956   vec_foreach (si, sorted_sis)
957   {
958     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
959       {
960         /* if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index)) */
961         /*   { */
962         /*     continue; */
963         /*   } */
964         sw_if_index = si->sw_if_index;
965         send_ip_details (am, reg, sw_if_index, mp->is_ipv6, mp->context);
966       }
967   }
968
969   vec_free (sorted_sis);
970 }
971
972 static void
973 set_ip6_flow_hash (vl_api_set_ip_flow_hash_t * mp)
974 {
975   vl_api_set_ip_flow_hash_reply_t *rmp;
976   int rv;
977   u32 table_id;
978   flow_hash_config_t flow_hash_config = 0;
979
980   table_id = ntohl (mp->vrf_id);
981
982 #define _(a,b) if (mp->a) flow_hash_config |= b;
983   foreach_flow_hash_bit;
984 #undef _
985
986   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
987
988   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
989 }
990
991 static void
992 set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
993 {
994   vl_api_set_ip_flow_hash_reply_t *rmp;
995   int rv;
996   u32 table_id;
997   flow_hash_config_t flow_hash_config = 0;
998
999   table_id = ntohl (mp->vrf_id);
1000
1001 #define _(a,b) if (mp->a) flow_hash_config |= b;
1002   foreach_flow_hash_bit;
1003 #undef _
1004
1005   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
1006
1007   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1008 }
1009
1010
1011 static void
1012 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t * mp)
1013 {
1014   if (mp->is_ipv6 == 0)
1015     set_ip4_flow_hash (mp);
1016   else
1017     set_ip6_flow_hash (mp);
1018 }
1019
1020 void
1021 vl_mfib_signal_send_one (vl_api_registration_t * reg,
1022                          u32 context, const mfib_signal_t * mfs)
1023 {
1024   vl_api_mfib_signal_details_t *mp;
1025   const mfib_prefix_t *prefix;
1026   mfib_table_t *mfib;
1027   mfib_itf_t *mfi;
1028
1029   mp = vl_msg_api_alloc (sizeof (*mp));
1030
1031   clib_memset (mp, 0, sizeof (*mp));
1032   mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS);
1033   mp->context = context;
1034
1035   mfi = mfib_itf_get (mfs->mfs_itf);
1036   prefix = mfib_entry_get_prefix (mfs->mfs_entry);
1037   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1038                          prefix->fp_proto);
1039   mp->table_id = ntohl (mfib->mft_table_id);
1040   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1041
1042   ip_mprefix_encode (prefix, &mp->prefix);
1043
1044   if (0 != mfs->mfs_buffer_len)
1045     {
1046       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1047
1048       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1049     }
1050   else
1051     {
1052       mp->ip_packet_len = 0;
1053     }
1054
1055   vl_api_send_msg (reg, (u8 *) mp);
1056 }
1057
1058 static void
1059 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1060 {
1061   vl_api_registration_t *reg;
1062
1063   reg = vl_api_client_index_to_registration (mp->client_index);
1064   if (!reg)
1065     return;
1066
1067   while (vl_api_can_send_msg (reg) && mfib_signal_send_one (reg, mp->context))
1068     ;
1069 }
1070
1071 static void
1072   vl_api_ip_container_proxy_add_del_t_handler
1073   (vl_api_ip_container_proxy_add_del_t * mp)
1074 {
1075   vl_api_ip_container_proxy_add_del_reply_t *rmp;
1076   vnet_ip_container_proxy_args_t args;
1077   int rv = 0;
1078   clib_error_t *error;
1079
1080   clib_memset (&args, 0, sizeof (args));
1081
1082   ip_prefix_decode (&mp->pfx, &args.prefix);
1083
1084   args.sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
1085   args.is_add = mp->is_add;
1086   if ((error = vnet_ip_container_proxy_add_del (&args)))
1087     {
1088       rv = clib_error_get_code (error);
1089       clib_error_report (error);
1090     }
1091
1092   REPLY_MACRO (VL_API_IP_CONTAINER_PROXY_ADD_DEL_REPLY);
1093 }
1094
1095 typedef struct ip_container_proxy_walk_ctx_t_
1096 {
1097   vl_api_registration_t *reg;
1098   u32 context;
1099 } ip_container_proxy_walk_ctx_t;
1100
1101 static int
1102 ip_container_proxy_send_details (const fib_prefix_t * pfx, u32 sw_if_index,
1103                                  void *args)
1104 {
1105   vl_api_ip_container_proxy_details_t *mp;
1106   ip_container_proxy_walk_ctx_t *ctx = args;
1107
1108   mp = vl_msg_api_alloc (sizeof (*mp));
1109   if (!mp)
1110     return 1;
1111
1112   clib_memset (mp, 0, sizeof (*mp));
1113   mp->_vl_msg_id = ntohs (VL_API_IP_CONTAINER_PROXY_DETAILS);
1114   mp->context = ctx->context;
1115
1116   mp->sw_if_index = ntohl (sw_if_index);
1117   ip_prefix_encode (pfx, &mp->prefix);
1118
1119   vl_api_send_msg (ctx->reg, (u8 *) mp);
1120
1121   return 1;
1122 }
1123
1124 static void
1125 vl_api_ip_container_proxy_dump_t_handler (vl_api_ip_container_proxy_dump_t *
1126                                           mp)
1127 {
1128   vl_api_registration_t *reg;
1129
1130   reg = vl_api_client_index_to_registration (mp->client_index);
1131   if (!reg)
1132     return;
1133
1134   ip_container_proxy_walk_ctx_t ctx = {
1135     .context = mp->context,
1136     .reg = reg,
1137   };
1138
1139   ip_container_proxy_walk (ip_container_proxy_send_details, &ctx);
1140 }
1141
1142 static void
1143 vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
1144 {
1145   int rv = 0;
1146   vl_api_ioam_enable_reply_t *rmp;
1147   clib_error_t *error;
1148
1149   /* Ignoring the profile id as currently a single profile
1150    * is supported */
1151   error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable,
1152                            mp->seqno, mp->analyse);
1153   if (error)
1154     {
1155       clib_error_report (error);
1156       rv = clib_error_get_code (error);
1157     }
1158
1159   REPLY_MACRO (VL_API_IOAM_ENABLE_REPLY);
1160 }
1161
1162 static void
1163 vl_api_ioam_disable_t_handler (vl_api_ioam_disable_t * mp)
1164 {
1165   int rv = 0;
1166   vl_api_ioam_disable_reply_t *rmp;
1167   clib_error_t *error;
1168
1169   error = clear_ioam_rewrite_fn ();
1170   if (error)
1171     {
1172       clib_error_report (error);
1173       rv = clib_error_get_code (error);
1174     }
1175
1176   REPLY_MACRO (VL_API_IOAM_DISABLE_REPLY);
1177 }
1178
1179 static void
1180   vl_api_ip_source_and_port_range_check_add_del_t_handler
1181   (vl_api_ip_source_and_port_range_check_add_del_t * mp)
1182 {
1183   vl_api_ip_source_and_port_range_check_add_del_reply_t *rmp;
1184   int rv = 0;
1185
1186   u8 is_add = mp->is_add;
1187   fib_prefix_t pfx;
1188   u16 *low_ports = 0;
1189   u16 *high_ports = 0;
1190   u32 vrf_id;
1191   u16 tmp_low, tmp_high;
1192   u8 num_ranges;
1193   int i;
1194
1195   ip_prefix_decode (&mp->prefix, &pfx);
1196
1197   // Validate port range
1198   num_ranges = mp->number_of_ranges;
1199   if (num_ranges > 32)
1200     {                           // This is size of array in VPE.API
1201       rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
1202       goto reply;
1203     }
1204
1205   vec_reset_length (low_ports);
1206   vec_reset_length (high_ports);
1207
1208   for (i = 0; i < num_ranges; i++)
1209     {
1210       tmp_low = mp->low_ports[i];
1211       tmp_high = mp->high_ports[i];
1212       // If tmp_low <= tmp_high then only need to check tmp_low = 0
1213       // If tmp_low <= tmp_high then only need to check tmp_high > 65535
1214       if (tmp_low > tmp_high || tmp_low == 0 || tmp_high > 65535)
1215         {
1216           rv = VNET_API_ERROR_INVALID_VALUE;
1217           goto reply;
1218         }
1219       vec_add1 (low_ports, tmp_low);
1220       vec_add1 (high_ports, tmp_high + 1);
1221     }
1222
1223   vrf_id = ntohl (mp->vrf_id);
1224
1225   if (vrf_id < 1)
1226     {
1227       rv = VNET_API_ERROR_INVALID_VALUE;
1228       goto reply;
1229     }
1230
1231
1232   if (FIB_PROTOCOL_IP6 == pfx.fp_proto)
1233     {
1234       rv = ip6_source_and_port_range_check_add_del (&pfx.fp_addr.ip6,
1235                                                     pfx.fp_len,
1236                                                     vrf_id,
1237                                                     low_ports,
1238                                                     high_ports, is_add);
1239     }
1240   else
1241     {
1242       rv = ip4_source_and_port_range_check_add_del (&pfx.fp_addr.ip4,
1243                                                     pfx.fp_len,
1244                                                     vrf_id,
1245                                                     low_ports,
1246                                                     high_ports, is_add);
1247     }
1248
1249 reply:
1250   vec_free (low_ports);
1251   vec_free (high_ports);
1252   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY);
1253 }
1254
1255 static void
1256   vl_api_ip_source_and_port_range_check_interface_add_del_t_handler
1257   (vl_api_ip_source_and_port_range_check_interface_add_del_t * mp)
1258 {
1259   vlib_main_t *vm = vlib_get_main ();
1260   vl_api_ip_source_and_port_range_check_interface_add_del_reply_t *rmp;
1261   ip4_main_t *im = &ip4_main;
1262   int rv;
1263   u32 sw_if_index;
1264   u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
1265   u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
1266   uword *p = 0;
1267   int i;
1268
1269   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] =
1270     ntohl (mp->tcp_out_vrf_id);
1271   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] =
1272     ntohl (mp->udp_out_vrf_id);
1273   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] =
1274     ntohl (mp->tcp_in_vrf_id);
1275   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] =
1276     ntohl (mp->udp_in_vrf_id);
1277
1278
1279   for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
1280     {
1281       if (vrf_id[i] != 0 && vrf_id[i] != ~0)
1282         {
1283           p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
1284
1285           if (p == 0)
1286             {
1287               rv = VNET_API_ERROR_INVALID_VALUE;
1288               goto reply;
1289             }
1290
1291           fib_index[i] = p[0];
1292         }
1293       else
1294         fib_index[i] = ~0;
1295     }
1296   sw_if_index = ntohl (mp->sw_if_index);
1297
1298   VALIDATE_SW_IF_INDEX (mp);
1299
1300   rv =
1301     set_ip_source_and_port_range_check (vm, fib_index, sw_if_index,
1302                                         mp->is_add);
1303
1304   BAD_SW_IF_INDEX_LABEL;
1305 reply:
1306
1307   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY);
1308 }
1309
1310 static void
1311   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1312   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1313 {
1314   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1315   ip6_address_t ip;
1316   int rv;
1317
1318   VALIDATE_SW_IF_INDEX (mp);
1319
1320   ip6_address_decode (mp->ip, &ip);
1321
1322   rv = ip6_link_set_local_address (ntohl (mp->sw_if_index), &ip);
1323
1324   BAD_SW_IF_INDEX_LABEL;
1325   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1326 }
1327
1328 static void
1329 vl_api_ip_table_replace_begin_t_handler (vl_api_ip_table_replace_begin_t * mp)
1330 {
1331   vl_api_ip_table_replace_begin_reply_t *rmp;
1332   fib_protocol_t fproto;
1333   u32 fib_index;
1334   int rv = 0;
1335
1336   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1337   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
1338
1339   if (INDEX_INVALID == fib_index)
1340     rv = VNET_API_ERROR_NO_SUCH_FIB;
1341   else
1342     {
1343       fib_table_mark (fib_index, fproto, FIB_SOURCE_API);
1344       mfib_table_mark (mfib_table_find (fproto, ntohl (mp->table.table_id)),
1345                        fproto, MFIB_SOURCE_API);
1346     }
1347   REPLY_MACRO (VL_API_IP_TABLE_REPLACE_BEGIN_REPLY);
1348 }
1349
1350 static void
1351 vl_api_ip_table_replace_end_t_handler (vl_api_ip_table_replace_end_t * mp)
1352 {
1353   vl_api_ip_table_replace_end_reply_t *rmp;
1354   fib_protocol_t fproto;
1355   u32 fib_index;
1356   int rv = 0;
1357
1358   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1359   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
1360
1361   if (INDEX_INVALID == fib_index)
1362     rv = VNET_API_ERROR_NO_SUCH_FIB;
1363   else
1364     {
1365       fib_table_sweep (fib_index, fproto, FIB_SOURCE_API);
1366       mfib_table_sweep (mfib_table_find
1367                         (fproto, ntohl (mp->table.table_id)), fproto,
1368                         MFIB_SOURCE_API);
1369     }
1370   REPLY_MACRO (VL_API_IP_TABLE_REPLACE_END_REPLY);
1371 }
1372
1373 static void
1374 vl_api_ip_table_flush_t_handler (vl_api_ip_table_flush_t * mp)
1375 {
1376   vl_api_ip_table_flush_reply_t *rmp;
1377   fib_protocol_t fproto;
1378   u32 fib_index;
1379   int rv = 0;
1380
1381   fproto = (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1382   fib_index = fib_table_find (fproto, ntohl (mp->table.table_id));
1383
1384   if (INDEX_INVALID == fib_index)
1385     rv = VNET_API_ERROR_NO_SUCH_FIB;
1386   else
1387     {
1388       vnet_main_t *vnm = vnet_get_main ();
1389       vnet_interface_main_t *im = &vnm->interface_main;
1390       vnet_sw_interface_t *si;
1391
1392       /* Shut down interfaces in this FIB / clean out intfc routes */
1393       /* *INDENT-OFF* */
1394       pool_foreach (si, im->sw_interfaces,
1395       ({
1396         if (fib_index == fib_table_get_index_for_sw_if_index (fproto,
1397                                                               si->sw_if_index))
1398           {
1399             u32 flags = si->flags;
1400             flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
1401             vnet_sw_interface_set_flags (vnm, si->sw_if_index, flags);
1402           }
1403       }));
1404       /* *INDENT-ON* */
1405
1406       fib_table_flush (fib_index, fproto, FIB_SOURCE_API);
1407       mfib_table_flush (mfib_table_find (fproto, ntohl (mp->table.table_id)),
1408                         fproto, MFIB_SOURCE_API);
1409     }
1410
1411   REPLY_MACRO (VL_API_IP_TABLE_FLUSH_REPLY);
1412 }
1413
1414 void
1415 vl_api_ip_reassembly_set_t_handler (vl_api_ip_reassembly_set_t * mp)
1416 {
1417   vl_api_ip_reassembly_set_reply_t *rmp;
1418   int rv = 0;
1419   switch ((vl_api_ip_reass_type_t) clib_net_to_host_u32 (mp->type))
1420     {
1421     case IP_REASS_TYPE_FULL:
1422       if (mp->is_ip6)
1423         {
1424           rv = ip6_full_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1425                                    clib_net_to_host_u32
1426                                    (mp->max_reassemblies),
1427                                    clib_net_to_host_u32
1428                                    (mp->max_reassembly_length),
1429                                    clib_net_to_host_u32
1430                                    (mp->expire_walk_interval_ms));
1431         }
1432       else
1433         {
1434           rv = ip4_full_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1435                                    clib_net_to_host_u32
1436                                    (mp->max_reassemblies),
1437                                    clib_net_to_host_u32
1438                                    (mp->max_reassembly_length),
1439                                    clib_net_to_host_u32
1440                                    (mp->expire_walk_interval_ms));
1441         }
1442       break;
1443     case IP_REASS_TYPE_SHALLOW_VIRTUAL:
1444       if (mp->is_ip6)
1445         {
1446           rv =
1447             ip6_sv_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1448                               clib_net_to_host_u32 (mp->max_reassemblies),
1449                               clib_net_to_host_u32
1450                               (mp->max_reassembly_length),
1451                               clib_net_to_host_u32
1452                               (mp->expire_walk_interval_ms));
1453         }
1454       else
1455         {
1456           rv = ip4_sv_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
1457                                  clib_net_to_host_u32 (mp->max_reassemblies),
1458                                  clib_net_to_host_u32
1459                                  (mp->max_reassembly_length),
1460                                  clib_net_to_host_u32
1461                                  (mp->expire_walk_interval_ms));
1462         }
1463       break;
1464     }
1465
1466   REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
1467 }
1468
1469 void
1470 vl_api_ip_reassembly_get_t_handler (vl_api_ip_reassembly_get_t * mp)
1471 {
1472   vl_api_registration_t *rp;
1473
1474   rp = vl_api_client_index_to_registration (mp->client_index);
1475   if (rp == 0)
1476     return;
1477
1478   vl_api_ip_reassembly_get_reply_t *rmp = vl_msg_api_alloc (sizeof (*rmp));
1479   clib_memset (rmp, 0, sizeof (*rmp));
1480   rmp->_vl_msg_id = ntohs (VL_API_IP_REASSEMBLY_GET_REPLY);
1481   rmp->context = mp->context;
1482   rmp->retval = 0;
1483   u32 timeout_ms;
1484   u32 max_reassemblies;
1485   u32 max_reassembly_length;
1486   u32 expire_walk_interval_ms;
1487   switch ((vl_api_ip_reass_type_t) clib_net_to_host_u32 (mp->type))
1488     {
1489     case IP_REASS_TYPE_FULL:
1490       if (mp->is_ip6)
1491         {
1492           rmp->is_ip6 = 1;
1493           ip6_full_reass_get (&timeout_ms, &max_reassemblies,
1494                               &max_reassembly_length,
1495                               &expire_walk_interval_ms);
1496         }
1497       else
1498         {
1499           rmp->is_ip6 = 0;
1500           ip4_full_reass_get (&timeout_ms, &max_reassemblies,
1501                               &max_reassembly_length,
1502                               &expire_walk_interval_ms);
1503         }
1504       break;
1505     case IP_REASS_TYPE_SHALLOW_VIRTUAL:
1506       if (mp->is_ip6)
1507         {
1508           rmp->is_ip6 = 1;
1509           ip6_sv_reass_get (&timeout_ms, &max_reassemblies,
1510                             &max_reassembly_length, &expire_walk_interval_ms);
1511         }
1512       else
1513         {
1514           rmp->is_ip6 = 0;
1515           ip4_sv_reass_get (&timeout_ms, &max_reassemblies,
1516                             &max_reassembly_length, &expire_walk_interval_ms);
1517         }
1518       break;
1519     }
1520   rmp->timeout_ms = clib_host_to_net_u32 (timeout_ms);
1521   rmp->max_reassemblies = clib_host_to_net_u32 (max_reassemblies);
1522   rmp->max_reassembly_length = clib_host_to_net_u32 (max_reassembly_length);
1523   rmp->expire_walk_interval_ms =
1524     clib_host_to_net_u32 (expire_walk_interval_ms);
1525   vl_api_send_msg (rp, (u8 *) rmp);
1526 }
1527
1528 void
1529   vl_api_ip_reassembly_enable_disable_t_handler
1530   (vl_api_ip_reassembly_enable_disable_t * mp)
1531 {
1532   vl_api_ip_reassembly_enable_disable_reply_t *rmp;
1533   int rv = 0;
1534   switch ((vl_api_ip_reass_type_t) clib_net_to_host_u32 (mp->type))
1535     {
1536     case IP_REASS_TYPE_FULL:
1537       rv =
1538         ip4_full_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
1539                                        mp->enable_ip4);
1540       if (0 == rv)
1541         rv =
1542           ip6_full_reass_enable_disable (clib_net_to_host_u32
1543                                          (mp->sw_if_index), mp->enable_ip6);
1544       break;
1545     case IP_REASS_TYPE_SHALLOW_VIRTUAL:
1546       rv =
1547         ip4_sv_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
1548                                      mp->enable_ip4);
1549       if (0 == rv)
1550         {
1551           rv =
1552             ip6_sv_reass_enable_disable (clib_net_to_host_u32
1553                                          (mp->sw_if_index), mp->enable_ip6);
1554         }
1555       break;
1556     }
1557
1558   REPLY_MACRO (VL_API_IP_REASSEMBLY_ENABLE_DISABLE_REPLY);
1559 }
1560
1561 typedef struct ip_punt_redirect_walk_ctx_t_
1562 {
1563   vl_api_registration_t *reg;
1564   u32 context;
1565 } ip_punt_redirect_walk_ctx_t;
1566
1567 static walk_rc_t
1568 send_ip_punt_redirect_details (u32 rx_sw_if_index,
1569                                const ip_punt_redirect_rx_t * ipr, void *arg)
1570 {
1571   ip_punt_redirect_walk_ctx_t *ctx = arg;
1572   vl_api_ip_punt_redirect_details_t *mp;
1573   fib_path_encode_ctx_t path_ctx = {
1574     .rpaths = NULL,
1575   };
1576
1577   mp = vl_msg_api_alloc (sizeof (*mp));
1578   if (!mp)
1579     return (WALK_STOP);;
1580
1581   clib_memset (mp, 0, sizeof (*mp));
1582   mp->_vl_msg_id = ntohs (VL_API_IP_PUNT_REDIRECT_DETAILS);
1583   mp->context = ctx->context;
1584
1585   fib_path_list_walk_w_ext (ipr->pl, NULL, fib_path_encode, &path_ctx);
1586
1587   mp->punt.rx_sw_if_index = htonl (rx_sw_if_index);
1588   mp->punt.tx_sw_if_index = htonl (path_ctx.rpaths[0].frp_sw_if_index);
1589
1590   ip_address_encode (&path_ctx.rpaths[0].frp_addr,
1591                      fib_proto_to_ip46 (ipr->fproto), &mp->punt.nh);
1592
1593   vl_api_send_msg (ctx->reg, (u8 *) mp);
1594
1595   vec_free (path_ctx.rpaths);
1596
1597   return (WALK_CONTINUE);
1598 }
1599
1600 static void
1601 vl_api_ip_punt_redirect_dump_t_handler (vl_api_ip_punt_redirect_dump_t * mp)
1602 {
1603   vl_api_registration_t *reg;
1604   fib_protocol_t fproto = FIB_PROTOCOL_IP4;
1605
1606   reg = vl_api_client_index_to_registration (mp->client_index);
1607   if (!reg)
1608     return;
1609
1610   if (mp->is_ipv6 == 1)
1611     fproto = FIB_PROTOCOL_IP6;
1612
1613   ip_punt_redirect_walk_ctx_t ctx = {
1614     .reg = reg,
1615     .context = mp->context,
1616   };
1617
1618   if (~0 != mp->sw_if_index)
1619     {
1620       u32 rx_sw_if_index;
1621       index_t pri;
1622
1623       rx_sw_if_index = ntohl (mp->sw_if_index);
1624       pri = ip_punt_redirect_find (fproto, rx_sw_if_index);
1625
1626       if (INDEX_INVALID == pri)
1627         return;
1628
1629       send_ip_punt_redirect_details (rx_sw_if_index,
1630                                      ip_punt_redirect_get (pri), &ctx);
1631     }
1632   else
1633     ip_punt_redirect_walk (fproto, send_ip_punt_redirect_details, &ctx);
1634 }
1635
1636 #define vl_msg_name_crc_list
1637 #include <vnet/ip/ip.api.h>
1638 #undef vl_msg_name_crc_list
1639
1640 static void
1641 setup_message_id_table (api_main_t * am)
1642 {
1643 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1644   foreach_vl_msg_name_crc_ip;
1645 #undef _
1646 }
1647
1648 static clib_error_t *
1649 ip_api_hookup (vlib_main_t * vm)
1650 {
1651   api_main_t *am = vlibapi_get_main ();
1652
1653 #define _(N,n)                                                  \
1654     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1655                            vl_api_##n##_t_handler,              \
1656                            vl_noop_handler,                     \
1657                            vl_api_##n##_t_endian,               \
1658                            vl_api_##n##_t_print,                \
1659                            sizeof(vl_api_##n##_t), 1);
1660   foreach_ip_api_msg;
1661 #undef _
1662
1663   /*
1664    * Mark the route add/del API as MP safe
1665    */
1666   am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL] = 1;
1667   am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL_REPLY] = 1;
1668
1669   /*
1670    * Set up the (msg_name, crc, message-id) table
1671    */
1672   setup_message_id_table (am);
1673
1674   return 0;
1675 }
1676
1677 VLIB_API_INIT_FUNCTION (ip_api_hookup);
1678
1679 /*
1680  * fd.io coding-style-patch-verification: ON
1681  *
1682  * Local Variables:
1683  * eval: (c-set-style "gnu")
1684  * End:
1685  */