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