4355d11e792ac0661c115ca2e37239dcfb460fbb
[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/ip/ip.h>
27 #include <vnet/ip/ip_neighbor.h>
28 #include <vnet/ip/ip6_neighbor.h>
29 #include <vnet/fib/fib_table.h>
30 #include <vnet/fib/fib_api.h>
31 #include <vnet/dpo/drop_dpo.h>
32 #include <vnet/dpo/receive_dpo.h>
33 #include <vnet/dpo/lookup_dpo.h>
34 #include <vnet/dpo/classify_dpo.h>
35 #include <vnet/dpo/ip_null_dpo.h>
36 #include <vnet/ethernet/arp_packet.h>
37 #include <vnet/mfib/ip6_mfib.h>
38 #include <vnet/mfib/ip4_mfib.h>
39 #include <vnet/mfib/mfib_signal.h>
40 #include <vnet/mfib/mfib_entry.h>
41 #include <vnet/ip/ip_source_and_port_range_check.h>
42 #include <vnet/fib/ip4_fib.h>
43 #include <vnet/fib/ip6_fib.h>
44 #include <vnet/ip/ip6_hop_by_hop.h>
45 #include <vnet/ip/ip4_reassembly.h>
46 #include <vnet/ip/ip6_reassembly.h>
47 #include <vnet/ethernet/arp.h>
48 #include <vnet/ip/ip_types_api.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
69 #define foreach_ip_api_msg                                              \
70 _(IP_FIB_DUMP, ip_fib_dump)                                             \
71 _(IP6_FIB_DUMP, ip6_fib_dump)                                           \
72 _(IP_MFIB_DUMP, ip_mfib_dump)                                           \
73 _(IP6_MFIB_DUMP, ip6_mfib_dump)                                         \
74 _(IP_NEIGHBOR_DUMP, ip_neighbor_dump)                                   \
75 _(IP_MROUTE_ADD_DEL, ip_mroute_add_del)                                 \
76 _(MFIB_SIGNAL_DUMP, mfib_signal_dump)                                   \
77 _(IP_ADDRESS_DUMP, ip_address_dump)                                     \
78 _(IP_UNNUMBERED_DUMP, ip_unnumbered_dump)                               \
79 _(IP_DUMP, ip_dump)                                                     \
80 _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del)                             \
81 _(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit)                       \
82 _(IP_PROBE_NEIGHBOR, ip_probe_neighbor)                                 \
83 _(IP_SCAN_NEIGHBOR_ENABLE_DISABLE, ip_scan_neighbor_enable_disable)     \
84 _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events)                             \
85 _(WANT_IP6_ND_EVENTS, want_ip6_nd_events)                               \
86 _(WANT_IP6_RA_EVENTS, want_ip6_ra_events)                               \
87 _(PROXY_ARP_ADD_DEL, proxy_arp_add_del)                                 \
88 _(PROXY_ARP_DUMP, proxy_arp_dump)                                       \
89 _(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable)       \
90  _(PROXY_ARP_INTFC_DUMP, proxy_arp_intfc_dump)                          \
91 _(RESET_FIB, reset_fib)                                                 \
92 _(IP_ADD_DEL_ROUTE, ip_add_del_route)                                   \
93 _(IP_TABLE_ADD_DEL, ip_table_add_del)                                   \
94 _(IP_PUNT_POLICE, ip_punt_police)                                       \
95 _(IP_PUNT_REDIRECT, ip_punt_redirect)                                   \
96 _(SET_IP_FLOW_HASH,set_ip_flow_hash)                                    \
97 _(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config)           \
98 _(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix)           \
99 _(IP6ND_PROXY_ADD_DEL, ip6nd_proxy_add_del)                             \
100 _(IP6ND_PROXY_DUMP, ip6nd_proxy_dump)                                   \
101 _(IP6ND_SEND_ROUTER_SOLICITATION, ip6nd_send_router_solicitation)       \
102 _(SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable )    \
103 _(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS,                              \
104   sw_interface_ip6_set_link_local_address)                              \
105 _(IP_CONTAINER_PROXY_ADD_DEL, ip_container_proxy_add_del)               \
106 _(IP_CONTAINER_PROXY_DUMP, ip_container_proxy_dump)                     \
107 _(IOAM_ENABLE, ioam_enable)                                             \
108 _(IOAM_DISABLE, ioam_disable)                                           \
109 _(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL,                               \
110   ip_source_and_port_range_check_add_del)                               \
111 _(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL,                     \
112   ip_source_and_port_range_check_interface_add_del)                     \
113 _(IP_REASSEMBLY_SET, ip_reassembly_set)                                 \
114 _(IP_REASSEMBLY_GET, ip_reassembly_get)                                 \
115 _(IP_REASSEMBLY_ENABLE_DISABLE, ip_reassembly_enable_disable)
116
117 extern void stats_dslock_with_hint (int hint, int tag);
118 extern void stats_dsunlock (void);
119
120 static void
121 send_ip_neighbor_details (u32 sw_if_index,
122                           u8 is_ipv6,
123                           u8 is_static,
124                           u8 * mac_address,
125                           u8 * ip_address, vl_api_registration_t * reg,
126                           u32 context)
127 {
128   vl_api_ip_neighbor_details_t *mp;
129
130   mp = vl_msg_api_alloc (sizeof (*mp));
131   memset (mp, 0, sizeof (*mp));
132   mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS);
133   mp->context = context;
134   mp->sw_if_index = htonl (sw_if_index);
135   mp->is_ipv6 = is_ipv6;
136   mp->is_static = is_static;
137   memcpy (mp->mac_address, mac_address, 6);
138   memcpy (mp->ip_address, ip_address, (is_ipv6) ? 16 : 4);
139
140   vl_api_send_msg (reg, (u8 *) mp);
141 }
142
143 static void
144 vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
145 {
146   vl_api_registration_t *reg;
147
148   reg = vl_api_client_index_to_registration (mp->client_index);
149   if (!reg)
150     return;
151
152   u32 sw_if_index = ntohl (mp->sw_if_index);
153
154   if (mp->is_ipv6)
155     {
156       ip6_neighbor_t *n, *ns;
157
158       ns = ip6_neighbors_entries (sw_if_index);
159       /* *INDENT-OFF* */
160       vec_foreach (n, ns)
161       {
162         send_ip_neighbor_details
163           (n->key.sw_if_index, mp->is_ipv6,
164            ((n->flags & IP6_NEIGHBOR_FLAG_STATIC) ? 1 : 0),
165            (u8 *) n->link_layer_address,
166            (u8 *) & (n->key.ip6_address.as_u8),
167            reg, mp->context);
168       }
169       /* *INDENT-ON* */
170       vec_free (ns);
171     }
172   else
173     {
174       ethernet_arp_ip4_entry_t *n, *ns;
175
176       ns = ip4_neighbor_entries (sw_if_index);
177       /* *INDENT-OFF* */
178       vec_foreach (n, ns)
179       {
180         send_ip_neighbor_details (n->sw_if_index, mp->is_ipv6,
181           ((n->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? 1 : 0),
182           (u8*) n->ethernet_address,
183           (u8*) & (n->ip4_address.as_u8),
184           reg, mp->context);
185       }
186       /* *INDENT-ON* */
187       vec_free (ns);
188     }
189 }
190
191 static void
192 send_ip_fib_details (vpe_api_main_t * am,
193                      vl_api_registration_t * reg,
194                      const fib_table_t * table,
195                      const fib_prefix_t * pfx,
196                      fib_route_path_encode_t * api_rpaths, u32 context)
197 {
198   vl_api_ip_fib_details_t *mp;
199   fib_route_path_encode_t *api_rpath;
200   vl_api_fib_path_t *fp;
201   int path_count;
202
203   path_count = vec_len (api_rpaths);
204   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
205   if (!mp)
206     return;
207   memset (mp, 0, sizeof (*mp));
208   mp->_vl_msg_id = ntohs (VL_API_IP_FIB_DETAILS);
209   mp->context = context;
210
211   mp->table_id = htonl (table->ft_table_id);
212   memcpy (mp->table_name, table->ft_desc,
213           clib_min (vec_len (table->ft_desc), sizeof (mp->table_name)));
214   mp->address_length = pfx->fp_len;
215   memcpy (mp->address, &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
216   mp->stats_index =
217     htonl (fib_table_entry_get_stats_index (table->ft_index, pfx));
218
219   mp->count = htonl (path_count);
220   fp = mp->path;
221   vec_foreach (api_rpath, api_rpaths)
222   {
223     fib_api_path_encode (api_rpath, fp);
224     fp++;
225   }
226
227   vl_api_send_msg (reg, (u8 *) mp);
228 }
229
230 typedef struct vl_api_ip_fib_dump_walk_ctx_t_
231 {
232   fib_node_index_t *feis;
233 } vl_api_ip_fib_dump_walk_ctx_t;
234
235 static fib_table_walk_rc_t
236 vl_api_ip_fib_dump_walk (fib_node_index_t fei, void *arg)
237 {
238   vl_api_ip_fib_dump_walk_ctx_t *ctx = arg;
239
240   vec_add1 (ctx->feis, fei);
241
242   return (FIB_TABLE_WALK_CONTINUE);
243 }
244
245 static void
246 vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
247 {
248   vpe_api_main_t *am = &vpe_api_main;
249   vl_api_registration_t *reg;
250   ip4_main_t *im = &ip4_main;
251   fib_table_t *fib_table;
252   fib_node_index_t *lfeip;
253   const fib_prefix_t *pfx;
254   u32 fib_index;
255   fib_route_path_encode_t *api_rpaths;
256   vl_api_ip_fib_dump_walk_ctx_t ctx = {
257     .feis = NULL,
258   };
259
260   reg = vl_api_client_index_to_registration (mp->client_index);
261   if (!reg)
262     return;
263
264   /* *INDENT-OFF* */
265   pool_foreach (fib_table, im->fibs,
266   ({
267     fib_table_walk(fib_table->ft_index,
268                    FIB_PROTOCOL_IP4,
269                    vl_api_ip_fib_dump_walk,
270                    &ctx);
271   }));
272   /* *INDENT-ON* */
273
274   vec_sort_with_function (ctx.feis, fib_entry_cmp_for_sort);
275
276   vec_foreach (lfeip, ctx.feis)
277   {
278     pfx = fib_entry_get_prefix (*lfeip);
279     fib_index = fib_entry_get_fib_index (*lfeip);
280     fib_table = fib_table_get (fib_index, pfx->fp_proto);
281     api_rpaths = NULL;
282     fib_entry_encode (*lfeip, &api_rpaths);
283     send_ip_fib_details (am, reg, fib_table, pfx, api_rpaths, mp->context);
284     vec_free (api_rpaths);
285   }
286
287   vec_free (ctx.feis);
288 }
289
290 static void
291 send_ip6_fib_details (vpe_api_main_t * am,
292                       vl_api_registration_t * reg,
293                       const fib_table_t * table,
294                       const fib_prefix_t * pfx,
295                       fib_route_path_encode_t * api_rpaths, u32 context)
296 {
297   vl_api_ip6_fib_details_t *mp;
298   fib_route_path_encode_t *api_rpath;
299   vl_api_fib_path_t *fp;
300   int path_count;
301
302   path_count = vec_len (api_rpaths);
303   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
304   if (!mp)
305     return;
306   memset (mp, 0, sizeof (*mp));
307   mp->_vl_msg_id = ntohs (VL_API_IP6_FIB_DETAILS);
308   mp->context = context;
309
310   mp->table_id = htonl (table->ft_table_id);
311   mp->address_length = pfx->fp_len;
312   memcpy (mp->address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
313   memcpy (mp->table_name, table->ft_desc,
314           clib_min (vec_len (table->ft_desc), sizeof (mp->table_name)));
315   mp->stats_index =
316     htonl (fib_table_entry_get_stats_index (table->ft_index, pfx));
317
318   mp->count = htonl (path_count);
319   fp = mp->path;
320   vec_foreach (api_rpath, api_rpaths)
321   {
322     fib_api_path_encode (api_rpath, fp);
323     fp++;
324   }
325
326   vl_api_send_msg (reg, (u8 *) mp);
327 }
328
329 typedef struct apt_ip6_fib_show_ctx_t_
330 {
331   u32 fib_index;
332   fib_node_index_t *entries;
333 } api_ip6_fib_show_ctx_t;
334
335 static void
336 api_ip6_fib_table_put_entries (clib_bihash_kv_24_8_t * kvp, void *arg)
337 {
338   api_ip6_fib_show_ctx_t *ctx = arg;
339
340   if ((kvp->key[2] >> 32) == ctx->fib_index)
341     {
342       vec_add1 (ctx->entries, kvp->value);
343     }
344 }
345
346 static void
347 api_ip6_fib_table_get_all (vl_api_registration_t * reg,
348                            vl_api_ip6_fib_dump_t * mp,
349                            fib_table_t * fib_table)
350 {
351   vpe_api_main_t *am = &vpe_api_main;
352   ip6_main_t *im6 = &ip6_main;
353   fib_node_index_t *fib_entry_index;
354   api_ip6_fib_show_ctx_t ctx = {
355     .fib_index = fib_table->ft_index,
356     .entries = NULL,
357   };
358   fib_route_path_encode_t *api_rpaths;
359   const fib_prefix_t *pfx;
360
361   BV (clib_bihash_foreach_key_value_pair)
362     ((BVT (clib_bihash) *) & im6->ip6_table[IP6_FIB_TABLE_NON_FWDING].
363      ip6_hash, api_ip6_fib_table_put_entries, &ctx);
364
365   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
366
367   vec_foreach (fib_entry_index, ctx.entries)
368   {
369     pfx = fib_entry_get_prefix (*fib_entry_index);
370     api_rpaths = NULL;
371     fib_entry_encode (*fib_entry_index, &api_rpaths);
372     send_ip6_fib_details (am, reg, fib_table, pfx, api_rpaths, mp->context);
373     vec_free (api_rpaths);
374   }
375
376   vec_free (ctx.entries);
377 }
378
379 static void
380 vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp)
381 {
382   vl_api_registration_t *reg;
383   ip6_main_t *im6 = &ip6_main;
384   fib_table_t *fib_table;
385
386   reg = vl_api_client_index_to_registration (mp->client_index);
387   if (!reg)
388     return;
389
390   /* *INDENT-OFF* */
391   pool_foreach (fib_table, im6->fibs,
392   ({
393     /* don't send link locals */
394     if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
395       continue;
396
397     api_ip6_fib_table_get_all(reg, mp, fib_table);
398   }));
399   /* *INDENT-ON* */
400 }
401
402 static void
403 send_ip_mfib_details (vl_api_registration_t * reg,
404                       u32 context, u32 table_id, fib_node_index_t mfei)
405 {
406   fib_route_path_encode_t *api_rpath, *api_rpaths = NULL;
407   vl_api_ip_mfib_details_t *mp;
408   mfib_entry_t *mfib_entry;
409   vl_api_fib_path_t *fp;
410   mfib_prefix_t pfx;
411   int path_count;
412
413   mfib_entry = mfib_entry_get (mfei);
414   mfib_entry_get_prefix (mfei, &pfx);
415   mfib_entry_encode (mfei, &api_rpaths);
416
417   path_count = vec_len (api_rpaths);
418   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
419   if (!mp)
420     return;
421   memset (mp, 0, sizeof (*mp));
422   mp->_vl_msg_id = ntohs (VL_API_IP_MFIB_DETAILS);
423   mp->context = context;
424
425   mp->rpf_id = mfib_entry->mfe_rpf_id;
426   mp->entry_flags = mfib_entry->mfe_flags;
427   mp->table_id = htonl (table_id);
428   mp->address_length = pfx.fp_len;
429   memcpy (mp->grp_address, &pfx.fp_grp_addr.ip4,
430           sizeof (pfx.fp_grp_addr.ip4));
431   memcpy (mp->src_address, &pfx.fp_src_addr.ip4,
432           sizeof (pfx.fp_src_addr.ip4));
433
434   mp->count = htonl (path_count);
435   fp = mp->path;
436   vec_foreach (api_rpath, api_rpaths)
437   {
438     fib_api_path_encode (api_rpath, fp);
439     fp++;
440   }
441   vec_free (api_rpaths);
442
443   vl_api_send_msg (reg, (u8 *) mp);
444 }
445
446 typedef struct vl_api_ip_mfib_dump_ctc_t_
447 {
448   fib_node_index_t *entries;
449 } vl_api_ip_mfib_dump_ctc_t;
450
451 static int
452 vl_api_ip_mfib_table_dump_walk (fib_node_index_t fei, void *arg)
453 {
454   vl_api_ip_mfib_dump_ctc_t *ctx = arg;
455
456   vec_add1 (ctx->entries, fei);
457
458   return (0);
459 }
460
461 static void
462 vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
463 {
464   vl_api_registration_t *reg;
465   ip4_main_t *im = &ip4_main;
466   mfib_table_t *mfib_table;
467   fib_node_index_t *mfeip;
468   vl_api_ip_mfib_dump_ctc_t ctx = {
469     .entries = NULL,
470   };
471
472   reg = vl_api_client_index_to_registration (mp->client_index);
473   if (!reg)
474     return;
475
476   /* *INDENT-OFF* */
477   pool_foreach (mfib_table, im->mfibs,
478   ({
479     ip4_mfib_table_walk(&mfib_table->v4,
480                         vl_api_ip_mfib_table_dump_walk,
481                         &ctx);
482
483     vec_sort_with_function (ctx.entries, mfib_entry_cmp_for_sort);
484
485     vec_foreach (mfeip, ctx.entries)
486     {
487       send_ip_mfib_details (reg, mp->context,
488                             mfib_table->mft_table_id,
489                             *mfeip);
490     }
491     vec_reset_length (ctx.entries);
492
493   }));
494   /* *INDENT-ON* */
495
496   vec_free (ctx.entries);
497 }
498
499 static void
500 send_ip6_mfib_details (vpe_api_main_t * am,
501                        vl_api_registration_t * reg,
502                        u32 table_id,
503                        mfib_prefix_t * pfx,
504                        fib_route_path_encode_t * api_rpaths, u32 context)
505 {
506   vl_api_ip6_mfib_details_t *mp;
507   fib_route_path_encode_t *api_rpath;
508   vl_api_fib_path_t *fp;
509   int path_count;
510
511   path_count = vec_len (api_rpaths);
512   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
513   if (!mp)
514     return;
515   memset (mp, 0, sizeof (*mp));
516   mp->_vl_msg_id = ntohs (VL_API_IP6_MFIB_DETAILS);
517   mp->context = context;
518
519   mp->table_id = htonl (table_id);
520   mp->address_length = pfx->fp_len;
521   memcpy (mp->grp_address, &pfx->fp_grp_addr.ip6,
522           sizeof (pfx->fp_grp_addr.ip6));
523   memcpy (mp->src_address, &pfx->fp_src_addr.ip6,
524           sizeof (pfx->fp_src_addr.ip6));
525
526   mp->count = htonl (path_count);
527   fp = mp->path;
528   vec_foreach (api_rpath, api_rpaths)
529   {
530     fib_api_path_encode (api_rpath, fp);
531     fp++;
532   }
533
534   vl_api_send_msg (reg, (u8 *) mp);
535 }
536
537 typedef struct vl_api_ip6_mfib_dump_ctc_t_
538 {
539   fib_node_index_t *entries;
540 } vl_api_ip6_mfib_dump_ctc_t;
541
542 static int
543 vl_api_ip6_mfib_table_dump_walk (fib_node_index_t fei, void *arg)
544 {
545   vl_api_ip6_mfib_dump_ctc_t *ctx = arg;
546
547   vec_add1 (ctx->entries, fei);
548
549   return (0);
550 }
551
552 static void
553 vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
554 {
555   vpe_api_main_t *am = &vpe_api_main;
556   vl_api_registration_t *reg;
557   ip6_main_t *im = &ip6_main;
558   mfib_table_t *mfib_table;
559   fib_node_index_t *mfeip;
560   mfib_prefix_t pfx;
561   fib_route_path_encode_t *api_rpaths = NULL;
562   vl_api_ip6_mfib_dump_ctc_t ctx = {
563     .entries = NULL,
564   };
565
566   reg = vl_api_client_index_to_registration (mp->client_index);
567   if (!reg)
568     return;
569
570
571   /* *INDENT-OFF* */
572   pool_foreach (mfib_table, im->mfibs,
573   ({
574     ip6_mfib_table_walk(&mfib_table->v6,
575                         vl_api_ip6_mfib_table_dump_walk,
576                         &ctx);
577
578     vec_sort_with_function (ctx.entries, mfib_entry_cmp_for_sort);
579
580     vec_foreach(mfeip, ctx.entries)
581     {
582       mfib_entry_get_prefix (*mfeip, &pfx);
583       mfib_entry_encode (*mfeip, &api_rpaths);
584       send_ip6_mfib_details (am, reg,
585                              mfib_table->mft_table_id,
586                              &pfx, api_rpaths,
587                              mp->context);
588     }
589     vec_reset_length (api_rpaths);
590     vec_reset_length (ctx.entries);
591
592   }));
593   /* *INDENT-ON* */
594
595   vec_free (ctx.entries);
596   vec_free (api_rpaths);
597 }
598
599 static void
600 vl_api_ip_punt_police_t_handler (vl_api_ip_punt_police_t * mp,
601                                  vlib_main_t * vm)
602 {
603   vl_api_ip_punt_police_reply_t *rmp;
604   int rv = 0;
605
606   if (mp->is_ip6)
607     ip6_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
608   else
609     ip4_punt_policer_add_del (mp->is_add, ntohl (mp->policer_index));
610
611   REPLY_MACRO (VL_API_IP_PUNT_POLICE_REPLY);
612 }
613
614 static void
615 vl_api_ip_punt_redirect_t_handler (vl_api_ip_punt_redirect_t * mp,
616                                    vlib_main_t * vm)
617 {
618   vl_api_ip_punt_redirect_reply_t *rmp;
619   int rv = 0;
620
621   if (mp->is_add)
622     {
623       ip46_address_t nh;
624
625       memset (&nh, 0, sizeof (nh));
626
627       if (mp->is_ip6)
628         {
629           memcpy (&nh.ip6, mp->nh, sizeof (nh.ip6));
630
631           ip6_punt_redirect_add (ntohl (mp->rx_sw_if_index),
632                                  ntohl (mp->tx_sw_if_index), &nh);
633         }
634       else
635         {
636           memcpy (&nh.ip4, mp->nh, sizeof (nh.ip4));
637
638           ip4_punt_redirect_add (ntohl (mp->rx_sw_if_index),
639                                  ntohl (mp->tx_sw_if_index), &nh);
640         }
641     }
642   else
643     {
644       if (mp->is_ip6)
645         {
646           ip6_punt_redirect_del (ntohl (mp->rx_sw_if_index));
647         }
648       else
649         {
650           ip4_punt_redirect_del (ntohl (mp->rx_sw_if_index));
651         }
652     }
653
654   REPLY_MACRO (VL_API_IP_PUNT_REDIRECT_REPLY);
655 }
656
657 static void
658 vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
659                                       vlib_main_t * vm)
660 {
661   ip46_address_t ip = ip46_address_initializer;
662   vl_api_ip_neighbor_add_del_reply_t *rmp;
663   ip_neighbor_flags_t flags;
664   u32 stats_index = ~0;
665   int rv = 0;
666
667   VALIDATE_SW_IF_INDEX (mp);
668
669   stats_dslock_with_hint (1 /* release hint */ , 7 /* tag */ );
670
671   flags = IP_NEIGHBOR_FLAG_NODE;
672   if (mp->is_static)
673     flags |= IP_NEIGHBOR_FLAG_STATIC;
674   if (mp->is_no_adj_fib)
675     flags |= IP_NEIGHBOR_FLAG_NO_ADJ_FIB;
676
677   if (mp->is_ipv6)
678     clib_memcpy (&ip.ip6, mp->dst_address, 16);
679   else
680     clib_memcpy (&ip.ip4, mp->dst_address, 4);
681
682   if (mp->is_add)
683     rv = ip_neighbor_add (&ip, mp->is_ipv6, mp->mac_address,
684                           ntohl (mp->sw_if_index), flags, &stats_index);
685   else
686     rv = ip_neighbor_del (&ip, mp->is_ipv6, ntohl (mp->sw_if_index));
687
688   stats_dsunlock ();
689
690   BAD_SW_IF_INDEX_LABEL;
691
692   /* *INDENT-OFF* */
693   REPLY_MACRO2 (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY,
694   ({
695     rmp->stats_index = htonl (stats_index);
696   }));
697   /* *INDENT-ON* */
698 }
699
700 void
701 ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api)
702 {
703   u32 fib_index, mfib_index;
704
705   /*
706    * ignore action on the default table - this is always present
707    * and cannot be added nor deleted from the API
708    */
709   if (0 != table_id)
710     {
711       /*
712        * The API holds only one lock on the table.
713        * i.e. it can be added many times via the API but needs to be
714        * deleted only once.
715        * The FIB index for unicast and multicast is not necessarily the
716        * same, since internal VPP systesm (like LISP and SR) create
717        * their own unicast tables.
718        */
719       fib_index = fib_table_find (fproto, table_id);
720       mfib_index = mfib_table_find (fproto, table_id);
721
722       if (~0 != fib_index)
723         {
724           fib_table_unlock (fib_index, fproto,
725                             (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI));
726         }
727       if (~0 != mfib_index)
728         {
729           mfib_table_unlock (mfib_index, fproto,
730                              (is_api ? MFIB_SOURCE_API : MFIB_SOURCE_CLI));
731         }
732     }
733 }
734
735 void
736 vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
737 {
738   vl_api_ip_table_add_del_reply_t *rmp;
739   fib_protocol_t fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
740   u32 table_id = ntohl (mp->table_id);
741   int rv = 0;
742
743   if (mp->is_add)
744     {
745       ip_table_create (fproto, table_id, 1, mp->name);
746     }
747   else
748     {
749       ip_table_delete (fproto, table_id, 1);
750     }
751
752   REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_REPLY);
753 }
754
755 int
756 add_del_route_t_handler (u8 is_multipath,
757                          u8 is_add,
758                          u8 is_drop,
759                          u8 is_unreach,
760                          u8 is_prohibit,
761                          u8 is_local,
762                          u8 is_multicast,
763                          u8 is_classify,
764                          u32 classify_table_index,
765                          u8 is_resolve_host,
766                          u8 is_resolve_attached,
767                          u8 is_interface_rx,
768                          u8 is_rpf_id,
769                          u8 is_dvr,
770                          u8 is_source_lookup,
771                          u8 is_udp_encap,
772                          u32 fib_index,
773                          const fib_prefix_t * prefix,
774                          dpo_proto_t next_hop_proto,
775                          const ip46_address_t * next_hop,
776                          u32 next_hop_id,
777                          u32 next_hop_sw_if_index,
778                          u8 next_hop_fib_index,
779                          u16 next_hop_weight,
780                          u16 next_hop_preference,
781                          mpls_label_t next_hop_via_label,
782                          fib_mpls_label_t * next_hop_out_label_stack)
783 {
784   vnet_classify_main_t *cm = &vnet_classify_main;
785   fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
786   fib_route_path_t path = {
787     .frp_proto = next_hop_proto,
788     .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
789     .frp_sw_if_index = next_hop_sw_if_index,
790     .frp_fib_index = next_hop_fib_index,
791     .frp_weight = next_hop_weight,
792     .frp_preference = next_hop_preference,
793     .frp_label_stack = next_hop_out_label_stack,
794   };
795   fib_route_path_t *paths = NULL;
796   fib_entry_flag_t entry_flags = FIB_ENTRY_FLAG_NONE;
797
798   /*
799    * the special INVALID label meams we are not recursing via a
800    * label. Exp-null value is never a valid via-label so that
801    * also means it's not a via-label and means clients that set
802    * it to 0 by default get the expected behaviour
803    */
804   if ((MPLS_LABEL_INVALID != next_hop_via_label) && (0 != next_hop_via_label))
805     {
806       path.frp_proto = DPO_PROTO_MPLS;
807       path.frp_local_label = next_hop_via_label;
808       path.frp_eos = MPLS_NON_EOS;
809     }
810   if (is_dvr)
811     path_flags |= FIB_ROUTE_PATH_DVR;
812   if (is_resolve_host)
813     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
814   if (is_resolve_attached)
815     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
816   if (is_interface_rx)
817     path_flags |= FIB_ROUTE_PATH_INTF_RX;
818   if (is_rpf_id)
819     path_flags |= FIB_ROUTE_PATH_RPF_ID;
820   if (is_source_lookup)
821     path_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
822   if (is_multicast)
823     entry_flags |= FIB_ENTRY_FLAG_MULTICAST;
824   if (is_udp_encap)
825     {
826       path_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
827       path.frp_udp_encap_id = next_hop_id;
828     }
829   if (path.frp_sw_if_index == ~0 && ip46_address_is_zero (&path.frp_addr)
830       && path.frp_fib_index != ~0)
831     {
832       path_flags |= FIB_ROUTE_PATH_DEAG;
833     }
834
835   path.frp_flags = path_flags;
836
837   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
838
839   if (is_drop || is_local || is_classify || is_unreach || is_prohibit)
840     {
841       /*
842        * special route types that link directly to the adj
843        */
844       if (is_add)
845         {
846           dpo_id_t dpo = DPO_INVALID;
847           dpo_proto_t dproto;
848
849           dproto = fib_proto_to_dpo (prefix->fp_proto);
850
851           if (is_drop)
852             ip_null_dpo_add_and_lock (dproto, IP_NULL_ACTION_NONE, &dpo);
853           else if (is_local)
854             receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo);
855           else if (is_unreach)
856             ip_null_dpo_add_and_lock (dproto,
857                                       IP_NULL_ACTION_SEND_ICMP_UNREACH, &dpo);
858           else if (is_prohibit)
859             ip_null_dpo_add_and_lock (dproto,
860                                       IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
861                                       &dpo);
862           else if (is_classify)
863             {
864               if (pool_is_free_index (cm->tables,
865                                       ntohl (classify_table_index)))
866                 {
867                   stats_dsunlock ();
868                   return VNET_API_ERROR_NO_SUCH_TABLE;
869                 }
870
871               dpo_set (&dpo, DPO_CLASSIFY, dproto,
872                        classify_dpo_create (dproto,
873                                             ntohl (classify_table_index)));
874             }
875           else
876             {
877               stats_dsunlock ();
878               return VNET_API_ERROR_NO_SUCH_TABLE;
879             }
880
881           fib_table_entry_special_dpo_update (fib_index,
882                                               prefix,
883                                               FIB_SOURCE_API,
884                                               FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
885           dpo_reset (&dpo);
886         }
887       else
888         {
889           fib_table_entry_special_remove (fib_index, prefix, FIB_SOURCE_API);
890         }
891     }
892   else if (is_multipath)
893     {
894       vec_add1 (paths, path);
895
896       if (is_add)
897         fib_table_entry_path_add2 (fib_index,
898                                    prefix,
899                                    FIB_SOURCE_API, entry_flags, paths);
900       else
901         fib_table_entry_path_remove2 (fib_index,
902                                       prefix, FIB_SOURCE_API, paths);
903
904       vec_free (paths);
905     }
906   else
907     {
908       if (is_add)
909         {
910           vec_add1 (paths, path);
911           fib_table_entry_update (fib_index,
912                                   prefix, FIB_SOURCE_API, entry_flags, paths);
913           vec_free (paths);
914         }
915       else
916         {
917           fib_table_entry_delete (fib_index, prefix, FIB_SOURCE_API);
918         }
919     }
920
921   stats_dsunlock ();
922   return (0);
923 }
924
925 int
926 add_del_route_check (fib_protocol_t table_proto,
927                      u32 table_id,
928                      u32 next_hop_sw_if_index,
929                      dpo_proto_t next_hop_table_proto,
930                      u32 next_hop_table_id,
931                      u8 is_rpf_id, u32 * fib_index, u32 * next_hop_fib_index)
932 {
933   vnet_main_t *vnm = vnet_get_main ();
934
935   *fib_index = fib_table_find (table_proto, ntohl (table_id));
936   if (~0 == *fib_index)
937     {
938       /* No such VRF, and we weren't asked to create one */
939       return VNET_API_ERROR_NO_SUCH_FIB;
940     }
941
942   if (!is_rpf_id && ~0 != ntohl (next_hop_sw_if_index))
943     {
944       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
945                               ntohl (next_hop_sw_if_index)))
946         {
947           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
948         }
949     }
950   else
951     {
952       fib_protocol_t fib_nh_proto;
953
954       if (next_hop_table_proto > DPO_PROTO_MPLS)
955         return (0);
956
957       fib_nh_proto = dpo_proto_to_fib (next_hop_table_proto);
958
959       if (is_rpf_id)
960         *next_hop_fib_index = mfib_table_find (fib_nh_proto,
961                                                ntohl (next_hop_table_id));
962       else
963         *next_hop_fib_index = fib_table_find (fib_nh_proto,
964                                               ntohl (next_hop_table_id));
965
966       if (~0 == *next_hop_fib_index)
967         {
968           /* No such VRF, and we weren't asked to create one */
969           return VNET_API_ERROR_NO_SUCH_FIB;
970         }
971     }
972
973   return (0);
974 }
975
976 static int
977 ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp,
978                              u32 * stats_index)
979 {
980   u32 fib_index, next_hop_fib_index;
981   fib_mpls_label_t *label_stack = NULL;
982   int rv, ii, n_labels;;
983
984   rv = add_del_route_check (FIB_PROTOCOL_IP4,
985                             mp->table_id,
986                             mp->next_hop_sw_if_index,
987                             DPO_PROTO_IP4,
988                             mp->next_hop_table_id,
989                             0, &fib_index, &next_hop_fib_index);
990
991   if (0 != rv)
992     return (rv);
993
994   fib_prefix_t pfx = {
995     .fp_len = mp->dst_address_length,
996     .fp_proto = FIB_PROTOCOL_IP4,
997   };
998   clib_memcpy (&pfx.fp_addr.ip4, mp->dst_address, sizeof (pfx.fp_addr.ip4));
999
1000   ip46_address_t nh;
1001   memset (&nh, 0, sizeof (nh));
1002   memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4));
1003
1004   n_labels = mp->next_hop_n_out_labels;
1005   if (n_labels == 0)
1006     ;
1007   else
1008     {
1009       vec_validate (label_stack, n_labels - 1);
1010       for (ii = 0; ii < n_labels; ii++)
1011         {
1012           label_stack[ii].fml_value =
1013             ntohl (mp->next_hop_out_label_stack[ii].label);
1014           label_stack[ii].fml_ttl = mp->next_hop_out_label_stack[ii].ttl;
1015           label_stack[ii].fml_exp = mp->next_hop_out_label_stack[ii].exp;
1016           label_stack[ii].fml_mode =
1017             (mp->next_hop_out_label_stack[ii].is_uniform ?
1018              FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE);
1019         }
1020     }
1021
1022   rv = add_del_route_t_handler (mp->is_multipath,
1023                                 mp->is_add,
1024                                 mp->is_drop,
1025                                 mp->is_unreach,
1026                                 mp->is_prohibit,
1027                                 mp->is_local, 0,
1028                                 mp->is_classify,
1029                                 mp->classify_table_index,
1030                                 mp->is_resolve_host,
1031                                 mp->is_resolve_attached, 0, 0,
1032                                 mp->is_dvr,
1033                                 mp->is_source_lookup,
1034                                 mp->is_udp_encap,
1035                                 fib_index, &pfx, DPO_PROTO_IP4,
1036                                 &nh,
1037                                 ntohl (mp->next_hop_id),
1038                                 ntohl (mp->next_hop_sw_if_index),
1039                                 next_hop_fib_index,
1040                                 mp->next_hop_weight,
1041                                 mp->next_hop_preference,
1042                                 ntohl (mp->next_hop_via_label), label_stack);
1043
1044   if (mp->is_add && 0 == rv)
1045     *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
1046
1047   return (rv);
1048 }
1049
1050 static int
1051 ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp,
1052                              u32 * stats_index)
1053 {
1054   fib_mpls_label_t *label_stack = NULL;
1055   u32 fib_index, next_hop_fib_index;
1056   int rv, ii, n_labels;;
1057
1058   rv = add_del_route_check (FIB_PROTOCOL_IP6,
1059                             mp->table_id,
1060                             mp->next_hop_sw_if_index,
1061                             DPO_PROTO_IP6,
1062                             mp->next_hop_table_id,
1063                             0, &fib_index, &next_hop_fib_index);
1064
1065   if (0 != rv)
1066     return (rv);
1067
1068   fib_prefix_t pfx = {
1069     .fp_len = mp->dst_address_length,
1070     .fp_proto = FIB_PROTOCOL_IP6,
1071   };
1072   clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6));
1073
1074   ip46_address_t nh;
1075   memset (&nh, 0, sizeof (nh));
1076   memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6));
1077
1078   n_labels = mp->next_hop_n_out_labels;
1079   if (n_labels == 0)
1080     ;
1081   else
1082     {
1083       vec_validate (label_stack, n_labels - 1);
1084       for (ii = 0; ii < n_labels; ii++)
1085         {
1086           label_stack[ii].fml_value =
1087             ntohl (mp->next_hop_out_label_stack[ii].label);
1088           label_stack[ii].fml_ttl = mp->next_hop_out_label_stack[ii].ttl;
1089           label_stack[ii].fml_exp = mp->next_hop_out_label_stack[ii].exp;
1090           label_stack[ii].fml_mode =
1091             (mp->next_hop_out_label_stack[ii].is_uniform ?
1092              FIB_MPLS_LSP_MODE_UNIFORM : FIB_MPLS_LSP_MODE_PIPE);
1093         }
1094     }
1095
1096   rv = add_del_route_t_handler (mp->is_multipath,
1097                                 mp->is_add,
1098                                 mp->is_drop,
1099                                 mp->is_unreach,
1100                                 mp->is_prohibit,
1101                                 mp->is_local, 0,
1102                                 mp->is_classify,
1103                                 mp->classify_table_index,
1104                                 mp->is_resolve_host,
1105                                 mp->is_resolve_attached, 0, 0,
1106                                 mp->is_dvr,
1107                                 mp->is_source_lookup,
1108                                 mp->is_udp_encap,
1109                                 fib_index, &pfx, DPO_PROTO_IP6,
1110                                 &nh, ntohl (mp->next_hop_id),
1111                                 ntohl (mp->next_hop_sw_if_index),
1112                                 next_hop_fib_index,
1113                                 mp->next_hop_weight,
1114                                 mp->next_hop_preference,
1115                                 ntohl (mp->next_hop_via_label), label_stack);
1116
1117   if (mp->is_add && 0 == rv)
1118     *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
1119
1120   return (rv);
1121 }
1122
1123 void
1124 vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
1125 {
1126   vl_api_ip_add_del_route_reply_t *rmp;
1127   u32 stats_index;
1128   int rv;
1129   vnet_main_t *vnm = vnet_get_main ();
1130
1131   vnm->api_errno = 0;
1132   stats_index = ~0;
1133
1134   if (mp->is_ipv6)
1135     rv = ip6_add_del_route_t_handler (mp, &stats_index);
1136   else
1137     rv = ip4_add_del_route_t_handler (mp, &stats_index);
1138
1139   rv = (rv == 0) ? vnm->api_errno : rv;
1140
1141   /* *INDENT-OFF* */
1142   REPLY_MACRO2 (VL_API_IP_ADD_DEL_ROUTE_REPLY,
1143   ({
1144     rmp->stats_index = htonl (stats_index);
1145   }))
1146   /* *INDENT-ON* */
1147 }
1148
1149 void
1150 ip_table_create (fib_protocol_t fproto,
1151                  u32 table_id, u8 is_api, const u8 * name)
1152 {
1153   u32 fib_index, mfib_index;
1154
1155   /*
1156    * ignore action on the default table - this is always present
1157    * and cannot be added nor deleted from the API
1158    */
1159   if (0 != table_id)
1160     {
1161       /*
1162        * The API holds only one lock on the table.
1163        * i.e. it can be added many times via the API but needs to be
1164        * deleted only once.
1165        * The FIB index for unicast and multicast is not necessarily the
1166        * same, since internal VPP systesm (like LISP and SR) create
1167        * their own unicast tables.
1168        */
1169       fib_index = fib_table_find (fproto, table_id);
1170       mfib_index = mfib_table_find (fproto, table_id);
1171
1172       if (~0 == fib_index)
1173         {
1174           fib_table_find_or_create_and_lock_w_name (fproto, table_id,
1175                                                     (is_api ?
1176                                                      FIB_SOURCE_API :
1177                                                      FIB_SOURCE_CLI), name);
1178         }
1179       if (~0 == mfib_index)
1180         {
1181           mfib_table_find_or_create_and_lock_w_name (fproto, table_id,
1182                                                      (is_api ?
1183                                                       MFIB_SOURCE_API :
1184                                                       MFIB_SOURCE_CLI), name);
1185         }
1186     }
1187 }
1188
1189 static int
1190 add_del_mroute_check (fib_protocol_t table_proto,
1191                       u32 table_id,
1192                       u32 next_hop_sw_if_index, u8 is_local, u32 * fib_index)
1193 {
1194   vnet_main_t *vnm = vnet_get_main ();
1195
1196   *fib_index = mfib_table_find (table_proto, ntohl (table_id));
1197   if (~0 == *fib_index)
1198     {
1199       /* No such table */
1200       return VNET_API_ERROR_NO_SUCH_FIB;
1201     }
1202
1203   if (~0 != ntohl (next_hop_sw_if_index))
1204     {
1205       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
1206                               ntohl (next_hop_sw_if_index)))
1207         {
1208           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
1209         }
1210     }
1211
1212   return (0);
1213 }
1214
1215 static fib_node_index_t
1216 mroute_add_del_handler (u8 is_add,
1217                         u8 is_local,
1218                         u32 fib_index,
1219                         const mfib_prefix_t * prefix,
1220                         dpo_proto_t nh_proto,
1221                         u32 entry_flags,
1222                         fib_rpf_id_t rpf_id,
1223                         u32 next_hop_sw_if_index,
1224                         ip46_address_t * nh, u32 itf_flags, u32 bier_imp)
1225 {
1226   fib_node_index_t mfib_entry_index = ~0;
1227
1228   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
1229
1230   fib_route_path_t path = {
1231     .frp_sw_if_index = next_hop_sw_if_index,
1232     .frp_proto = nh_proto,
1233     .frp_addr = *nh,
1234   };
1235
1236   if (is_local)
1237     path.frp_flags |= FIB_ROUTE_PATH_LOCAL;
1238
1239   if (DPO_PROTO_BIER == nh_proto)
1240     {
1241       path.frp_bier_imp = bier_imp;
1242       path.frp_flags = FIB_ROUTE_PATH_BIER_IMP;
1243     }
1244   else if (!is_local && ~0 == next_hop_sw_if_index)
1245     {
1246       mfib_entry_index = mfib_table_entry_update (fib_index, prefix,
1247                                                   MFIB_SOURCE_API,
1248                                                   rpf_id, entry_flags);
1249       goto done;
1250     }
1251
1252   if (is_add)
1253     {
1254       mfib_entry_index = mfib_table_entry_path_update (fib_index, prefix,
1255                                                        MFIB_SOURCE_API,
1256                                                        &path, itf_flags);
1257     }
1258   else
1259     {
1260       mfib_table_entry_path_remove (fib_index, prefix,
1261                                     MFIB_SOURCE_API, &path);
1262     }
1263
1264 done:
1265   stats_dsunlock ();
1266   return (mfib_entry_index);
1267 }
1268
1269 static int
1270 api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp,
1271                               u32 * stats_index)
1272 {
1273   fib_node_index_t mfib_entry_index;
1274   fib_protocol_t fproto;
1275   dpo_proto_t nh_proto;
1276   ip46_address_t nh;
1277   u32 fib_index;
1278   int rv;
1279
1280   nh_proto = mp->next_hop_afi;
1281   fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1282   rv = add_del_mroute_check (fproto,
1283                              mp->table_id,
1284                              mp->next_hop_sw_if_index,
1285                              mp->is_local, &fib_index);
1286
1287   if (0 != rv)
1288     return (rv);
1289
1290   mfib_prefix_t pfx = {
1291     .fp_len = ntohs (mp->grp_address_length),
1292     .fp_proto = fproto,
1293   };
1294
1295   if (FIB_PROTOCOL_IP4 == fproto)
1296     {
1297       clib_memcpy (&pfx.fp_grp_addr.ip4, mp->grp_address,
1298                    sizeof (pfx.fp_grp_addr.ip4));
1299       clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address,
1300                    sizeof (pfx.fp_src_addr.ip4));
1301       memset (&nh.ip6, 0, sizeof (nh.ip6));
1302       clib_memcpy (&nh.ip4, mp->nh_address, sizeof (nh.ip4));
1303       if (!ip46_address_is_zero (&pfx.fp_src_addr))
1304         pfx.fp_len = 64;
1305     }
1306   else
1307     {
1308       clib_memcpy (&pfx.fp_grp_addr.ip6, mp->grp_address,
1309                    sizeof (pfx.fp_grp_addr.ip6));
1310       clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address,
1311                    sizeof (pfx.fp_src_addr.ip6));
1312       clib_memcpy (&nh.ip6, mp->nh_address, sizeof (nh.ip6));
1313       if (!ip46_address_is_zero (&pfx.fp_src_addr))
1314         pfx.fp_len = 256;
1315     }
1316
1317   mfib_entry_index = mroute_add_del_handler (mp->is_add,
1318                                              mp->is_local,
1319                                              fib_index, &pfx,
1320                                              nh_proto,
1321                                              ntohl (mp->entry_flags),
1322                                              ntohl (mp->rpf_id),
1323                                              ntohl (mp->next_hop_sw_if_index),
1324                                              &nh,
1325                                              ntohl (mp->itf_flags),
1326                                              ntohl (mp->bier_imp));
1327
1328   if (~0 != mfib_entry_index)
1329     *stats_index = mfib_entry_get_stats_index (mfib_entry_index);
1330
1331   return (rv);
1332 }
1333
1334 void
1335 vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
1336 {
1337   vl_api_ip_mroute_add_del_reply_t *rmp;
1338   vnet_main_t *vnm;
1339   u32 stats_index;
1340   int rv;
1341
1342   vnm = vnet_get_main ();
1343   vnm->api_errno = 0;
1344   stats_index = ~0;
1345
1346   rv = api_mroute_add_del_t_handler (mp, &stats_index);
1347
1348   /* *INDENT-OFF* */
1349   REPLY_MACRO2 (VL_API_IP_MROUTE_ADD_DEL_REPLY,
1350   ({
1351     rmp->stats_index = htonl (stats_index);
1352   }));
1353   /* *INDENT-ON* */
1354 }
1355
1356 static void
1357 send_ip_details (vpe_api_main_t * am,
1358                  vl_api_registration_t * reg, u32 sw_if_index, u8 is_ipv6,
1359                  u32 context)
1360 {
1361   vl_api_ip_details_t *mp;
1362
1363   mp = vl_msg_api_alloc (sizeof (*mp));
1364   memset (mp, 0, sizeof (*mp));
1365   mp->_vl_msg_id = ntohs (VL_API_IP_DETAILS);
1366
1367   mp->sw_if_index = ntohl (sw_if_index);
1368   mp->is_ipv6 = is_ipv6;
1369   mp->context = context;
1370
1371   vl_api_send_msg (reg, (u8 *) mp);
1372 }
1373
1374 static void
1375 send_ip_address_details (vpe_api_main_t * am,
1376                          vl_api_registration_t * reg,
1377                          u8 * ip, u16 prefix_length,
1378                          u32 sw_if_index, u8 is_ipv6, u32 context)
1379 {
1380   vl_api_ip_address_details_t *mp;
1381
1382   mp = vl_msg_api_alloc (sizeof (*mp));
1383   memset (mp, 0, sizeof (*mp));
1384   mp->_vl_msg_id = ntohs (VL_API_IP_ADDRESS_DETAILS);
1385
1386   if (is_ipv6)
1387     {
1388       clib_memcpy (&mp->ip, ip, sizeof (mp->ip));
1389     }
1390   else
1391     {
1392       u32 *tp = (u32 *) mp->ip;
1393       *tp = *(u32 *) ip;
1394     }
1395   mp->prefix_length = prefix_length;
1396   mp->context = context;
1397   mp->sw_if_index = htonl (sw_if_index);
1398   mp->is_ipv6 = is_ipv6;
1399
1400   vl_api_send_msg (reg, (u8 *) mp);
1401 }
1402
1403 static void
1404 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
1405 {
1406   vpe_api_main_t *am = &vpe_api_main;
1407   vl_api_registration_t *reg;
1408   ip6_address_t *r6;
1409   ip4_address_t *r4;
1410   ip6_main_t *im6 = &ip6_main;
1411   ip4_main_t *im4 = &ip4_main;
1412   ip_lookup_main_t *lm6 = &im6->lookup_main;
1413   ip_lookup_main_t *lm4 = &im4->lookup_main;
1414   ip_interface_address_t *ia = 0;
1415   u32 sw_if_index = ~0;
1416   int rv __attribute__ ((unused)) = 0;
1417
1418   VALIDATE_SW_IF_INDEX (mp);
1419
1420   sw_if_index = ntohl (mp->sw_if_index);
1421
1422   reg = vl_api_client_index_to_registration (mp->client_index);
1423   if (!reg)
1424     return;
1425
1426   if (mp->is_ipv6)
1427     {
1428       /* *INDENT-OFF* */
1429       /* Do not send subnet details of the IP-interface for
1430        * unnumbered interfaces. otherwise listening clients
1431        * will be confused that the subnet is applied on more
1432        * than one interface */
1433       foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
1434       ({
1435         r6 = ip_interface_address_get_address (lm6, ia);
1436         u16 prefix_length = ia->address_length;
1437         send_ip_address_details(am, reg, (u8*)r6, prefix_length,
1438                                 sw_if_index, 1, mp->context);
1439       }));
1440       /* *INDENT-ON* */
1441     }
1442   else
1443     {
1444       /* *INDENT-OFF* */
1445       foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1446       ({
1447         r4 = ip_interface_address_get_address (lm4, ia);
1448         u16 prefix_length = ia->address_length;
1449         send_ip_address_details(am, reg, (u8*)r4, prefix_length,
1450                                 sw_if_index, 0, mp->context);
1451       }));
1452       /* *INDENT-ON* */
1453     }
1454
1455   BAD_SW_IF_INDEX_LABEL;
1456 }
1457
1458 static void
1459 send_ip_unnumbered_details (vpe_api_main_t * am,
1460                             vl_api_registration_t * reg,
1461                             u32 sw_if_index, u32 ip_sw_if_index, u32 context)
1462 {
1463   vl_api_ip_unnumbered_details_t *mp;
1464
1465   mp = vl_msg_api_alloc (sizeof (*mp));
1466   memset (mp, 0, sizeof (*mp));
1467   mp->_vl_msg_id = ntohs (VL_API_IP_UNNUMBERED_DETAILS);
1468
1469   mp->context = context;
1470   mp->sw_if_index = htonl (sw_if_index);
1471   mp->ip_sw_if_index = htonl (ip_sw_if_index);
1472
1473   vl_api_send_msg (reg, (u8 *) mp);
1474 }
1475
1476 static void
1477 vl_api_ip_unnumbered_dump_t_handler (vl_api_ip_unnumbered_dump_t * mp)
1478 {
1479   vnet_main_t *vnm = vnet_get_main ();
1480   vnet_interface_main_t *im = &vnm->interface_main;
1481   int rv __attribute__ ((unused)) = 0;
1482   vpe_api_main_t *am = &vpe_api_main;
1483   vl_api_registration_t *reg;
1484   vnet_sw_interface_t *si;
1485   u32 sw_if_index;
1486
1487   sw_if_index = ntohl (mp->sw_if_index);
1488
1489   reg = vl_api_client_index_to_registration (mp->client_index);
1490   if (!reg)
1491     return;
1492
1493   if (~0 != sw_if_index)
1494     {
1495       VALIDATE_SW_IF_INDEX (mp);
1496
1497       si = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
1498
1499       if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1500         {
1501           send_ip_unnumbered_details (am, reg,
1502                                       sw_if_index,
1503                                       si->unnumbered_sw_if_index,
1504                                       mp->context);
1505         }
1506     }
1507   else
1508     {
1509       /* *INDENT-OFF* */
1510       pool_foreach (si, im->sw_interfaces,
1511       ({
1512         if ((si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1513           {
1514             send_ip_unnumbered_details(am, reg,
1515                                        si->sw_if_index,
1516                                        si->unnumbered_sw_if_index,
1517                                        mp->context);
1518           }
1519       }));
1520       /* *INDENT-ON* */
1521     }
1522
1523   BAD_SW_IF_INDEX_LABEL;
1524 }
1525
1526 static void
1527 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
1528 {
1529   vpe_api_main_t *am = &vpe_api_main;
1530   vnet_main_t *vnm = vnet_get_main ();
1531   vlib_main_t *vm = vlib_get_main ();
1532   vnet_interface_main_t *im = &vnm->interface_main;
1533   vl_api_registration_t *reg;
1534   vnet_sw_interface_t *si, *sorted_sis;
1535   u32 sw_if_index = ~0;
1536
1537   reg = vl_api_client_index_to_registration (mp->client_index);
1538   if (!reg)
1539     return;
1540
1541   /* Gather interfaces. */
1542   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1543   _vec_len (sorted_sis) = 0;
1544   /* *INDENT-OFF* */
1545   pool_foreach (si, im->sw_interfaces,
1546   ({
1547     vec_add1 (sorted_sis, si[0]);
1548   }));
1549   /* *INDENT-ON* */
1550
1551   vec_foreach (si, sorted_sis)
1552   {
1553     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1554       {
1555         if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index))
1556           {
1557             continue;
1558           }
1559         sw_if_index = si->sw_if_index;
1560         send_ip_details (am, reg, sw_if_index, mp->is_ipv6, mp->context);
1561       }
1562   }
1563 }
1564
1565 static void
1566 set_ip6_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1567 {
1568   vl_api_set_ip_flow_hash_reply_t *rmp;
1569   int rv;
1570   u32 table_id;
1571   flow_hash_config_t flow_hash_config = 0;
1572
1573   table_id = ntohl (mp->vrf_id);
1574
1575 #define _(a,b) if (mp->a) flow_hash_config |= b;
1576   foreach_flow_hash_bit;
1577 #undef _
1578
1579   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
1580
1581   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1582 }
1583
1584 static void
1585 set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1586 {
1587   vl_api_set_ip_flow_hash_reply_t *rmp;
1588   int rv;
1589   u32 table_id;
1590   flow_hash_config_t flow_hash_config = 0;
1591
1592   table_id = ntohl (mp->vrf_id);
1593
1594 #define _(a,b) if (mp->a) flow_hash_config |= b;
1595   foreach_flow_hash_bit;
1596 #undef _
1597
1598   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
1599
1600   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1601 }
1602
1603
1604 static void
1605 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t * mp)
1606 {
1607   if (mp->is_ipv6 == 0)
1608     set_ip4_flow_hash (mp);
1609   else
1610     set_ip6_flow_hash (mp);
1611 }
1612
1613 static void
1614   vl_api_sw_interface_ip6nd_ra_config_t_handler
1615   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
1616 {
1617   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
1618   vlib_main_t *vm = vlib_get_main ();
1619   int rv = 0;
1620   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
1621     default_router;
1622
1623   is_no = mp->is_no == 1;
1624   suppress = mp->suppress == 1;
1625   managed = mp->managed == 1;
1626   other = mp->other == 1;
1627   ll_option = mp->ll_option == 1;
1628   send_unicast = mp->send_unicast == 1;
1629   cease = mp->cease == 1;
1630   default_router = mp->default_router == 1;
1631
1632   VALIDATE_SW_IF_INDEX (mp);
1633
1634   rv = ip6_neighbor_ra_config (vm, ntohl (mp->sw_if_index),
1635                                suppress, managed, other,
1636                                ll_option, send_unicast, cease,
1637                                default_router, ntohl (mp->lifetime),
1638                                ntohl (mp->initial_count),
1639                                ntohl (mp->initial_interval),
1640                                ntohl (mp->max_interval),
1641                                ntohl (mp->min_interval), is_no);
1642
1643   BAD_SW_IF_INDEX_LABEL;
1644
1645   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
1646 }
1647
1648 static void
1649   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
1650   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
1651 {
1652   vlib_main_t *vm = vlib_get_main ();
1653   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
1654   int rv = 0;
1655   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
1656
1657   VALIDATE_SW_IF_INDEX (mp);
1658
1659   is_no = mp->is_no == 1;
1660   use_default = mp->use_default == 1;
1661   no_advertise = mp->no_advertise == 1;
1662   off_link = mp->off_link == 1;
1663   no_autoconfig = mp->no_autoconfig == 1;
1664   no_onlink = mp->no_onlink == 1;
1665
1666   rv = ip6_neighbor_ra_prefix (vm, ntohl (mp->sw_if_index),
1667                                (ip6_address_t *) mp->address,
1668                                mp->address_length, use_default,
1669                                ntohl (mp->val_lifetime),
1670                                ntohl (mp->pref_lifetime), no_advertise,
1671                                off_link, no_autoconfig, no_onlink, is_no);
1672
1673   BAD_SW_IF_INDEX_LABEL;
1674   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
1675 }
1676
1677 static void
1678 send_ip6nd_proxy_details (vl_api_registration_t * reg,
1679                           u32 context,
1680                           const ip46_address_t * addr, u32 sw_if_index)
1681 {
1682   vl_api_ip6nd_proxy_details_t *mp;
1683
1684   mp = vl_msg_api_alloc (sizeof (*mp));
1685   memset (mp, 0, sizeof (*mp));
1686   mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
1687   mp->context = context;
1688   mp->sw_if_index = htonl (sw_if_index);
1689   memcpy (mp->address, addr, 16);
1690
1691   vl_api_send_msg (reg, (u8 *) mp);
1692 }
1693
1694 typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
1695 {
1696   u32 *indices;
1697 } api_ip6nd_proxy_fib_table_walk_ctx_t;
1698
1699 static fib_table_walk_rc_t
1700 api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
1701 {
1702   api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
1703
1704   if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
1705     {
1706       vec_add1 (ctx->indices, fei);
1707     }
1708
1709   return (FIB_TABLE_WALK_CONTINUE);
1710 }
1711
1712 static void
1713 vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
1714 {
1715   ip6_main_t *im6 = &ip6_main;
1716   fib_table_t *fib_table;
1717   api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
1718     .indices = NULL,
1719   };
1720   fib_node_index_t *feip;
1721   const fib_prefix_t *pfx;
1722   vl_api_registration_t *reg;
1723
1724   reg = vl_api_client_index_to_registration (mp->client_index);
1725   if (!reg)
1726     return;
1727
1728   /* *INDENT-OFF* */
1729   pool_foreach (fib_table, im6->fibs,
1730   ({
1731     fib_table_walk(fib_table->ft_index,
1732                    FIB_PROTOCOL_IP6,
1733                    api_ip6nd_proxy_fib_table_walk,
1734                    &ctx);
1735   }));
1736   /* *INDENT-ON* */
1737
1738   vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
1739
1740   vec_foreach (feip, ctx.indices)
1741   {
1742     pfx = fib_entry_get_prefix (*feip);
1743
1744     send_ip6nd_proxy_details (reg,
1745                               mp->context,
1746                               &pfx->fp_addr,
1747                               fib_entry_get_resolving_interface (*feip));
1748   }
1749
1750   vec_free (ctx.indices);
1751 }
1752
1753 static void
1754 vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
1755 {
1756   vl_api_ip6nd_proxy_add_del_reply_t *rmp;
1757   int rv = 0;
1758
1759   VALIDATE_SW_IF_INDEX (mp);
1760
1761   rv = ip6_neighbor_proxy_add_del (ntohl (mp->sw_if_index),
1762                                    (ip6_address_t *) mp->address, mp->is_del);
1763
1764   BAD_SW_IF_INDEX_LABEL;
1765   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
1766 }
1767
1768 static void
1769   vl_api_ip6nd_send_router_solicitation_t_handler
1770   (vl_api_ip6nd_send_router_solicitation_t * mp)
1771 {
1772   vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
1773   icmp6_send_router_solicitation_params_t params;
1774   vlib_main_t *vm = vlib_get_main ();
1775   int rv = 0;
1776
1777   VALIDATE_SW_IF_INDEX (mp);
1778
1779   BAD_SW_IF_INDEX_LABEL;
1780   REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
1781
1782   if (rv != 0)
1783     return;
1784
1785   params.irt = ntohl (mp->irt);
1786   params.mrt = ntohl (mp->mrt);
1787   params.mrc = ntohl (mp->mrc);
1788   params.mrd = ntohl (mp->mrd);
1789
1790   icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
1791                                   &params);
1792 }
1793
1794 static void
1795   vl_api_sw_interface_ip6_enable_disable_t_handler
1796   (vl_api_sw_interface_ip6_enable_disable_t * mp)
1797 {
1798   vlib_main_t *vm = vlib_get_main ();
1799   vl_api_sw_interface_ip6_enable_disable_reply_t *rmp;
1800   vnet_main_t *vnm = vnet_get_main ();
1801   int rv = 0;
1802   clib_error_t *error;
1803
1804   vnm->api_errno = 0;
1805
1806   VALIDATE_SW_IF_INDEX (mp);
1807
1808   error =
1809     (mp->enable == 1) ? enable_ip6_interface (vm,
1810                                               ntohl (mp->sw_if_index)) :
1811     disable_ip6_interface (vm, ntohl (mp->sw_if_index));
1812
1813   if (error)
1814     {
1815       clib_error_report (error);
1816       rv = VNET_API_ERROR_UNSPECIFIED;
1817     }
1818   else
1819     {
1820       rv = vnm->api_errno;
1821     }
1822
1823   BAD_SW_IF_INDEX_LABEL;
1824
1825   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
1826 }
1827
1828 static void
1829   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1830   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1831 {
1832   vlib_main_t *vm = vlib_get_main ();
1833   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1834   int rv = 0;
1835   clib_error_t *error;
1836   vnet_main_t *vnm = vnet_get_main ();
1837
1838   vnm->api_errno = 0;
1839
1840   VALIDATE_SW_IF_INDEX (mp);
1841
1842   error = set_ip6_link_local_address (vm,
1843                                       ntohl (mp->sw_if_index),
1844                                       (ip6_address_t *) mp->address);
1845   if (error)
1846     {
1847       clib_error_report (error);
1848       rv = VNET_API_ERROR_UNSPECIFIED;
1849     }
1850   else
1851     {
1852       rv = vnm->api_errno;
1853     }
1854
1855   BAD_SW_IF_INDEX_LABEL;
1856
1857   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1858 }
1859
1860 void
1861 vl_mfib_signal_send_one (vl_api_registration_t * reg,
1862                          u32 context, const mfib_signal_t * mfs)
1863 {
1864   vl_api_mfib_signal_details_t *mp;
1865   mfib_prefix_t prefix;
1866   mfib_table_t *mfib;
1867   mfib_itf_t *mfi;
1868
1869   mp = vl_msg_api_alloc (sizeof (*mp));
1870
1871   memset (mp, 0, sizeof (*mp));
1872   mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS);
1873   mp->context = context;
1874
1875   mfi = mfib_itf_get (mfs->mfs_itf);
1876   mfib_entry_get_prefix (mfs->mfs_entry, &prefix);
1877   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1878                          prefix.fp_proto);
1879   mp->table_id = ntohl (mfib->mft_table_id);
1880   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1881
1882   if (FIB_PROTOCOL_IP4 == prefix.fp_proto)
1883     {
1884       mp->grp_address_len = ntohs (prefix.fp_len);
1885
1886       memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4);
1887       if (prefix.fp_len > 32)
1888         {
1889           memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4);
1890         }
1891     }
1892   else
1893     {
1894       mp->grp_address_len = ntohs (prefix.fp_len);
1895
1896       ASSERT (0);
1897     }
1898
1899   if (0 != mfs->mfs_buffer_len)
1900     {
1901       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1902
1903       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1904     }
1905   else
1906     {
1907       mp->ip_packet_len = 0;
1908     }
1909
1910   vl_api_send_msg (reg, (u8 *) mp);
1911 }
1912
1913 static void
1914 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1915 {
1916   vl_api_registration_t *reg;
1917
1918   reg = vl_api_client_index_to_registration (mp->client_index);
1919   if (!reg)
1920     return;
1921
1922   while (vl_api_can_send_msg (reg) && mfib_signal_send_one (reg, mp->context))
1923     ;
1924 }
1925
1926 static void
1927   vl_api_ip_container_proxy_add_del_t_handler
1928   (vl_api_ip_container_proxy_add_del_t * mp)
1929 {
1930   vl_api_ip_container_proxy_add_del_reply_t *rmp;
1931   vnet_ip_container_proxy_args_t args;
1932   int rv = 0;
1933   clib_error_t *error;
1934
1935   memset (&args, 0, sizeof (args));
1936   ip_set (&args.prefix.fp_addr, mp->ip, mp->is_ip4);
1937   args.prefix.fp_len = mp->plen ? mp->plen : (mp->is_ip4 ? 32 : 128);
1938   args.sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
1939   args.is_add = mp->is_add;
1940   if ((error = vnet_ip_container_proxy_add_del (&args)))
1941     {
1942       rv = clib_error_get_code (error);
1943       clib_error_report (error);
1944     }
1945
1946   REPLY_MACRO (VL_API_IP_CONTAINER_PROXY_ADD_DEL_REPLY);
1947 }
1948
1949 typedef struct ip_container_proxy_walk_ctx_t_
1950 {
1951   vl_api_registration_t *reg;
1952   u32 context;
1953 } ip_container_proxy_walk_ctx_t;
1954
1955 static int
1956 ip_container_proxy_send_details (const fib_prefix_t * pfx, u32 sw_if_index,
1957                                  void *args)
1958 {
1959   vl_api_ip_container_proxy_details_t *mp;
1960   ip_container_proxy_walk_ctx_t *ctx = args;
1961
1962   mp = vl_msg_api_alloc (sizeof (*mp));
1963   if (!mp)
1964     return 1;
1965
1966   memset (mp, 0, sizeof (*mp));
1967   mp->_vl_msg_id = ntohs (VL_API_IP_CONTAINER_PROXY_DETAILS);
1968   mp->context = ctx->context;
1969
1970   mp->sw_if_index = ntohl (sw_if_index);
1971   ip_prefix_encode (pfx, &mp->prefix);
1972
1973   vl_api_send_msg (ctx->reg, (u8 *) mp);
1974
1975   return 1;
1976 }
1977
1978 static void
1979 vl_api_ip_container_proxy_dump_t_handler (vl_api_ip_container_proxy_dump_t *
1980                                           mp)
1981 {
1982   vl_api_registration_t *reg;
1983
1984   reg = vl_api_client_index_to_registration (mp->client_index);
1985   if (!reg)
1986     return;
1987
1988   ip_container_proxy_walk_ctx_t ctx = {
1989     .context = mp->context,
1990     .reg = reg,
1991   };
1992
1993   ip_container_proxy_walk (ip_container_proxy_send_details, &ctx);
1994 }
1995
1996 static void
1997 vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
1998 {
1999   int rv = 0;
2000   vl_api_ioam_enable_reply_t *rmp;
2001   clib_error_t *error;
2002
2003   /* Ignoring the profile id as currently a single profile
2004    * is supported */
2005   error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable,
2006                            mp->seqno, mp->analyse);
2007   if (error)
2008     {
2009       clib_error_report (error);
2010       rv = clib_error_get_code (error);
2011     }
2012
2013   REPLY_MACRO (VL_API_IOAM_ENABLE_REPLY);
2014 }
2015
2016 static void
2017 vl_api_ioam_disable_t_handler (vl_api_ioam_disable_t * mp)
2018 {
2019   int rv = 0;
2020   vl_api_ioam_disable_reply_t *rmp;
2021   clib_error_t *error;
2022
2023   error = clear_ioam_rewrite_fn ();
2024   if (error)
2025     {
2026       clib_error_report (error);
2027       rv = clib_error_get_code (error);
2028     }
2029
2030   REPLY_MACRO (VL_API_IOAM_DISABLE_REPLY);
2031 }
2032
2033 static void
2034   vl_api_ip_source_and_port_range_check_add_del_t_handler
2035   (vl_api_ip_source_and_port_range_check_add_del_t * mp)
2036 {
2037   vl_api_ip_source_and_port_range_check_add_del_reply_t *rmp;
2038   int rv = 0;
2039
2040   u8 is_ipv6 = mp->is_ipv6;
2041   u8 is_add = mp->is_add;
2042   u8 mask_length = mp->mask_length;
2043   ip4_address_t ip4_addr;
2044   ip6_address_t ip6_addr;
2045   u16 *low_ports = 0;
2046   u16 *high_ports = 0;
2047   u32 vrf_id;
2048   u16 tmp_low, tmp_high;
2049   u8 num_ranges;
2050   int i;
2051
2052   // Validate port range
2053   num_ranges = mp->number_of_ranges;
2054   if (num_ranges > 32)
2055     {                           // This is size of array in VPE.API
2056       rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
2057       goto reply;
2058     }
2059
2060   vec_reset_length (low_ports);
2061   vec_reset_length (high_ports);
2062
2063   for (i = 0; i < num_ranges; i++)
2064     {
2065       tmp_low = mp->low_ports[i];
2066       tmp_high = mp->high_ports[i];
2067       // If tmp_low <= tmp_high then only need to check tmp_low = 0
2068       // If tmp_low <= tmp_high then only need to check tmp_high > 65535
2069       if (tmp_low > tmp_high || tmp_low == 0 || tmp_high > 65535)
2070         {
2071           rv = VNET_API_ERROR_INVALID_VALUE;
2072           goto reply;
2073         }
2074       vec_add1 (low_ports, tmp_low);
2075       vec_add1 (high_ports, tmp_high + 1);
2076     }
2077
2078   // Validate mask_length
2079   if ((is_ipv6 && mask_length > 128) || (!is_ipv6 && mask_length > 32))
2080     {
2081       rv = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
2082       goto reply;
2083     }
2084
2085   vrf_id = ntohl (mp->vrf_id);
2086
2087   if (vrf_id < 1)
2088     {
2089       rv = VNET_API_ERROR_INVALID_VALUE;
2090       goto reply;
2091     }
2092
2093
2094   if (is_ipv6)
2095     {
2096       clib_memcpy (ip6_addr.as_u8, mp->address, sizeof (ip6_addr.as_u8));
2097       rv = ip6_source_and_port_range_check_add_del (&ip6_addr,
2098                                                     mask_length,
2099                                                     vrf_id,
2100                                                     low_ports,
2101                                                     high_ports, is_add);
2102     }
2103   else
2104     {
2105       clib_memcpy (ip4_addr.data, mp->address, sizeof (ip4_addr));
2106       rv = ip4_source_and_port_range_check_add_del (&ip4_addr,
2107                                                     mask_length,
2108                                                     vrf_id,
2109                                                     low_ports,
2110                                                     high_ports, is_add);
2111     }
2112
2113 reply:
2114   vec_free (low_ports);
2115   vec_free (high_ports);
2116   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY);
2117 }
2118
2119 static void
2120   vl_api_ip_source_and_port_range_check_interface_add_del_t_handler
2121   (vl_api_ip_source_and_port_range_check_interface_add_del_t * mp)
2122 {
2123   vlib_main_t *vm = vlib_get_main ();
2124   vl_api_ip_source_and_port_range_check_interface_add_del_reply_t *rmp;
2125   ip4_main_t *im = &ip4_main;
2126   int rv;
2127   u32 sw_if_index;
2128   u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
2129   u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
2130   uword *p = 0;
2131   int i;
2132
2133   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] =
2134     ntohl (mp->tcp_out_vrf_id);
2135   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] =
2136     ntohl (mp->udp_out_vrf_id);
2137   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] =
2138     ntohl (mp->tcp_in_vrf_id);
2139   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] =
2140     ntohl (mp->udp_in_vrf_id);
2141
2142
2143   for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
2144     {
2145       if (vrf_id[i] != 0 && vrf_id[i] != ~0)
2146         {
2147           p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
2148
2149           if (p == 0)
2150             {
2151               rv = VNET_API_ERROR_INVALID_VALUE;
2152               goto reply;
2153             }
2154
2155           fib_index[i] = p[0];
2156         }
2157       else
2158         fib_index[i] = ~0;
2159     }
2160   sw_if_index = ntohl (mp->sw_if_index);
2161
2162   VALIDATE_SW_IF_INDEX (mp);
2163
2164   rv =
2165     set_ip_source_and_port_range_check (vm, fib_index, sw_if_index,
2166                                         mp->is_add);
2167
2168   BAD_SW_IF_INDEX_LABEL;
2169 reply:
2170
2171   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY);
2172 }
2173
2174 #define IP4_ARP_EVENT 3
2175 #define IP6_ND_EVENT 4
2176
2177 static int arp_change_delete_callback (u32 pool_index, u8 * notused);
2178 static int nd_change_delete_callback (u32 pool_index, u8 * notused);
2179 static vlib_node_registration_t ip_resolver_process_node;
2180
2181 static void
2182 handle_ip4_arp_event (u32 pool_index)
2183 {
2184   vpe_api_main_t *vam = &vpe_api_main;
2185   vnet_main_t *vnm = vam->vnet_main;
2186   vlib_main_t *vm = vam->vlib_main;
2187   vl_api_ip4_arp_event_t *event;
2188   vl_api_ip4_arp_event_t *mp;
2189   vl_api_registration_t *reg;
2190
2191   /* Client can cancel, die, etc. */
2192   if (pool_is_free_index (vam->arp_events, pool_index))
2193     return;
2194
2195   event = pool_elt_at_index (vam->arp_events, pool_index);
2196
2197   reg = vl_api_client_index_to_registration (event->client_index);
2198   if (!reg)
2199     {
2200       (void) vnet_add_del_ip4_arp_change_event
2201         (vnm, arp_change_delete_callback,
2202          event->pid, &event->address,
2203          ip_resolver_process_node.index, IP4_ARP_EVENT,
2204          ~0 /* pool index, notused */ , 0 /* is_add */ );
2205       return;
2206     }
2207
2208   if (vl_api_can_send_msg (reg))
2209     {
2210       mp = vl_msg_api_alloc (sizeof (*mp));
2211       clib_memcpy (mp, event, sizeof (*mp));
2212       vl_api_send_msg (reg, (u8 *) mp);
2213     }
2214   else
2215     {
2216       static f64 last_time;
2217       /*
2218        * Throttle syslog msgs.
2219        * It's pretty tempting to just revoke the registration...
2220        */
2221       if (vlib_time_now (vm) > last_time + 10.0)
2222         {
2223           clib_warning ("arp event for %U to pid %d: queue stuffed!",
2224                         format_ip4_address, &event->address, event->pid);
2225           last_time = vlib_time_now (vm);
2226         }
2227     }
2228 }
2229
2230 static void
2231 handle_ip6_nd_event (u32 pool_index)
2232 {
2233   vpe_api_main_t *vam = &vpe_api_main;
2234   vnet_main_t *vnm = vam->vnet_main;
2235   vlib_main_t *vm = vam->vlib_main;
2236   vl_api_ip6_nd_event_t *event;
2237   vl_api_ip6_nd_event_t *mp;
2238   vl_api_registration_t *reg;
2239
2240   /* Client can cancel, die, etc. */
2241   if (pool_is_free_index (vam->nd_events, pool_index))
2242     return;
2243
2244   event = pool_elt_at_index (vam->nd_events, pool_index);
2245
2246   reg = vl_api_client_index_to_registration (event->client_index);
2247   if (!reg)
2248     {
2249       (void) vnet_add_del_ip6_nd_change_event
2250         (vnm, nd_change_delete_callback,
2251          event->pid, &event->address,
2252          ip_resolver_process_node.index, IP6_ND_EVENT,
2253          ~0 /* pool index, notused */ , 0 /* is_add */ );
2254       return;
2255     }
2256
2257   if (vl_api_can_send_msg (reg))
2258     {
2259       mp = vl_msg_api_alloc (sizeof (*mp));
2260       clib_memcpy (mp, event, sizeof (*mp));
2261       vl_api_send_msg (reg, (u8 *) mp);
2262     }
2263   else
2264     {
2265       static f64 last_time;
2266       /*
2267        * Throttle syslog msgs.
2268        * It's pretty tempting to just revoke the registration...
2269        */
2270       if (vlib_time_now (vm) > last_time + 10.0)
2271         {
2272           clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!",
2273                         format_ip6_address, &event->address, event->pid);
2274           last_time = vlib_time_now (vm);
2275         }
2276     }
2277 }
2278
2279 static uword
2280 resolver_process (vlib_main_t * vm,
2281                   vlib_node_runtime_t * rt, vlib_frame_t * f)
2282 {
2283   volatile f64 timeout = 100.0;
2284   volatile uword *event_data = 0;
2285
2286   while (1)
2287     {
2288       vlib_process_wait_for_event_or_clock (vm, timeout);
2289
2290       uword event_type =
2291         vlib_process_get_events (vm, (uword **) & event_data);
2292
2293       int i;
2294       switch (event_type)
2295         {
2296         case IP4_ARP_EVENT:
2297           for (i = 0; i < vec_len (event_data); i++)
2298             handle_ip4_arp_event (event_data[i]);
2299           break;
2300
2301         case IP6_ND_EVENT:
2302           for (i = 0; i < vec_len (event_data); i++)
2303             handle_ip6_nd_event (event_data[i]);
2304           break;
2305
2306         case ~0:                /* timeout */
2307           break;
2308         }
2309
2310       vec_reset_length (event_data);
2311     }
2312   return 0;                     /* or not */
2313 }
2314
2315 /* *INDENT-OFF* */
2316 VLIB_REGISTER_NODE (ip_resolver_process_node,static) = {
2317   .function = resolver_process,
2318   .type = VLIB_NODE_TYPE_PROCESS,
2319   .name = "ip-route-resolver-process",
2320 };
2321 /* *INDENT-ON* */
2322
2323 static int
2324 nd_change_data_callback (u32 pool_index, u8 * new_mac,
2325                          u32 sw_if_index, ip6_address_t * address)
2326 {
2327   vpe_api_main_t *am = &vpe_api_main;
2328   vl_api_ip6_nd_event_t *event;
2329
2330   if (pool_is_free_index (am->nd_events, pool_index))
2331     return 1;
2332
2333   event = pool_elt_at_index (am->nd_events, pool_index);
2334   if (eth_mac_equal (event->new_mac, new_mac) &&
2335       sw_if_index == ntohl (event->sw_if_index))
2336     {
2337       return 1;
2338     }
2339
2340   clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
2341   event->sw_if_index = htonl (sw_if_index);
2342   return 0;
2343 }
2344
2345 static int
2346 arp_change_delete_callback (u32 pool_index, u8 * notused)
2347 {
2348   vpe_api_main_t *am = &vpe_api_main;
2349
2350   if (pool_is_free_index (am->arp_events, pool_index))
2351     return 1;
2352
2353   pool_put_index (am->arp_events, pool_index);
2354   return 0;
2355 }
2356
2357 static int
2358 nd_change_delete_callback (u32 pool_index, u8 * notused)
2359 {
2360   vpe_api_main_t *am = &vpe_api_main;
2361
2362   if (pool_is_free_index (am->nd_events, pool_index))
2363     return 1;
2364
2365   pool_put_index (am->nd_events, pool_index);
2366   return 0;
2367 }
2368
2369 static vlib_node_registration_t wc_arp_process_node;
2370
2371 enum
2372 { WC_ARP_REPORT, WC_ND_REPORT, RA_REPORT, REPORT_MAX };
2373
2374 static uword
2375 wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
2376 {
2377   /* These cross the longjmp  boundry (vlib_process_wait_for_event)
2378    * and need to be volatile - to prevent them from being optimized into
2379    * a register - which could change during suspension */
2380
2381   volatile wc_arp_report_t arp_prev = { 0 };
2382   volatile wc_nd_report_t nd_prev = { 0 };
2383   volatile f64 last_arp = vlib_time_now (vm);
2384   volatile f64 last_nd = vlib_time_now (vm);
2385
2386   while (1)
2387     {
2388       vlib_process_wait_for_event (vm);
2389       uword event_type = WC_ARP_REPORT;
2390       void *event_data = vlib_process_get_event_data (vm, &event_type);
2391
2392       f64 now = vlib_time_now (vm);
2393       int i;
2394       if (event_type == WC_ARP_REPORT)
2395         {
2396           wc_arp_report_t *arp_events = event_data;
2397           for (i = 0; i < vec_len (arp_events); i++)
2398             {
2399               /* discard dup event */
2400               if (arp_prev.ip4 == arp_events[i].ip4 &&
2401                   eth_mac_equal ((u8 *) arp_prev.mac, arp_events[i].mac) &&
2402                   arp_prev.sw_if_index == arp_events[i].sw_if_index &&
2403                   (now - last_arp) < 10.0)
2404                 {
2405                   continue;
2406                 }
2407               arp_prev = arp_events[i];
2408               last_arp = now;
2409               vpe_client_registration_t *reg;
2410             /* *INDENT-OFF* */
2411             pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations,
2412             ({
2413               vl_api_registration_t *vl_reg;
2414               vl_reg = vl_api_client_index_to_registration (reg->client_index);
2415               ASSERT (vl_reg != NULL);
2416               if (reg && vl_api_can_send_msg (vl_reg))
2417                 {
2418                   vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event);
2419                   memset (event, 0, sizeof *event);
2420                   event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
2421                   event->client_index = reg->client_index;
2422                   event->pid = reg->client_pid;
2423                   event->mac_ip = 1;
2424                   event->address = arp_events[i].ip4;
2425                   event->sw_if_index = htonl(arp_events[i].sw_if_index);
2426                   memcpy(event->new_mac, arp_events[i].mac, sizeof event->new_mac);
2427                   vl_api_send_msg (vl_reg, (u8 *) event);
2428                 }
2429             }));
2430             /* *INDENT-ON* */
2431             }
2432         }
2433       else if (event_type == WC_ND_REPORT)
2434         {
2435           wc_nd_report_t *nd_events = event_data;
2436           for (i = 0; i < vec_len (nd_events); i++)
2437             {
2438               /* discard dup event */
2439               if (ip6_address_is_equal
2440                   ((ip6_address_t *) & nd_prev.ip6, &nd_events[i].ip6)
2441                   && eth_mac_equal ((u8 *) nd_prev.mac, nd_events[i].mac)
2442                   && nd_prev.sw_if_index == nd_events[i].sw_if_index
2443                   && (now - last_nd) < 10.0)
2444                 {
2445                   continue;
2446                 }
2447               nd_prev = nd_events[i];
2448               last_nd = now;
2449               vpe_client_registration_t *reg;
2450               /* *INDENT-OFF* */
2451               pool_foreach(reg, vpe_api_main.wc_ip6_nd_events_registrations,
2452               ({
2453                 vl_api_registration_t *vl_reg;
2454                 vl_reg = vl_api_client_index_to_registration (reg->client_index);
2455                 if (vl_reg && vl_api_can_send_msg (vl_reg))
2456                   {
2457                     vl_api_ip6_nd_event_t * event = vl_msg_api_alloc (sizeof *event);
2458                     memset (event, 0, sizeof *event);
2459                     event->_vl_msg_id = htons (VL_API_IP6_ND_EVENT);
2460                     event->client_index = reg->client_index;
2461                     event->pid = reg->client_pid;
2462                     event->mac_ip = 1;
2463                     memcpy(event->address, nd_events[i].ip6.as_u8, sizeof event->address);
2464                     event->sw_if_index = htonl(nd_events[i].sw_if_index);
2465                     memcpy(event->new_mac, nd_events[i].mac, sizeof event->new_mac);
2466                     vl_api_send_msg (vl_reg, (u8 *) event);
2467                   }
2468               }));
2469             /* *INDENT-ON* */
2470             }
2471         }
2472       else if (event_type == RA_REPORT)
2473         {
2474           ra_report_t *ra_events = event_data;
2475           for (i = 0; i < vec_len (ra_events); i++)
2476             {
2477               ip6_neighbor_public_main_t *npm = &ip6_neighbor_public_main;
2478               call_ip6_neighbor_callbacks (&ra_events[i],
2479                                            npm->ra_report_functions);
2480
2481               vpe_client_registration_t *reg;
2482               /* *INDENT-OFF* */
2483               pool_foreach(reg, vpe_api_main.ip6_ra_events_registrations,
2484               ({
2485                 vl_api_registration_t *vl_reg;
2486                 vl_reg =
2487                   vl_api_client_index_to_registration (reg->client_index);
2488                 if (vl_reg && vl_api_can_send_msg (vl_reg))
2489                   {
2490                     u32 event_size =
2491                       sizeof (vl_api_ip6_ra_event_t) +
2492                       vec_len (ra_events[i].prefixes) *
2493                       sizeof (vl_api_ip6_ra_prefix_info_t);
2494                     vl_api_ip6_ra_event_t *event =
2495                       vl_msg_api_alloc (event_size);
2496                     memset (event, 0, event_size);
2497                     event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT);
2498                     event->client_index = reg->client_index;
2499                     event->pid = reg->client_pid;
2500
2501                     event->sw_if_index = clib_host_to_net_u32 (ra_events[i].sw_if_index);
2502
2503                     memcpy (event->router_address, ra_events[i].router_address, 16);
2504
2505                     event->current_hop_limit = ra_events[i].current_hop_limit;
2506                     event->flags = ra_events[i].flags;
2507                     event->router_lifetime_in_sec =
2508                       clib_host_to_net_u16 (ra_events
2509                                             [i].router_lifetime_in_sec);
2510                     event->neighbor_reachable_time_in_msec =
2511                       clib_host_to_net_u32 (ra_events
2512                                             [i].neighbor_reachable_time_in_msec);
2513                     event->time_in_msec_between_retransmitted_neighbor_solicitations
2514                       =
2515                       clib_host_to_net_u32 (ra_events
2516                                             [i].time_in_msec_between_retransmitted_neighbor_solicitations);
2517
2518                     event->n_prefixes =
2519                       clib_host_to_net_u32 (vec_len (ra_events[i].prefixes));
2520                     vl_api_ip6_ra_prefix_info_t *prefix =
2521                       (typeof (prefix)) event->prefixes;
2522                     u32 j;
2523                     for (j = 0; j < vec_len (ra_events[i].prefixes); j++)
2524                       {
2525                         ra_report_prefix_info_t *info =
2526                           &ra_events[i].prefixes[j];
2527                         memcpy (prefix->dst_address, info->dst_address.as_u8,
2528                                 16);
2529                         prefix->dst_address_length = info->dst_address_length;
2530                         prefix->flags = info->flags;
2531                         prefix->valid_time =
2532                           clib_host_to_net_u32 (info->valid_time);
2533                         prefix->preferred_time =
2534                           clib_host_to_net_u32 (info->preferred_time);
2535                         prefix++;
2536                       }
2537
2538                     vl_api_send_msg (vl_reg, (u8 *) event);
2539                   }
2540               }));
2541               /* *INDENT-ON* */
2542               vec_free (ra_events[i].prefixes);
2543             }
2544         }
2545       vlib_process_put_event_data (vm, event_data);
2546     }
2547
2548   return 0;
2549 }
2550
2551 /* *INDENT-OFF* */
2552 VLIB_REGISTER_NODE (wc_arp_process_node,static) = {
2553   .function = wc_arp_process,
2554   .type = VLIB_NODE_TYPE_PROCESS,
2555   .name = "wildcard-ip4-arp-publisher-process",
2556 };
2557 /* *INDENT-ON* */
2558
2559 static int
2560 arp_change_data_callback (u32 pool_index, u8 * new_mac,
2561                           u32 sw_if_index, u32 address)
2562 {
2563   vpe_api_main_t *am = &vpe_api_main;
2564   vl_api_ip4_arp_event_t *event;
2565
2566   if (pool_is_free_index (am->arp_events, pool_index))
2567     return 1;
2568
2569   event = pool_elt_at_index (am->arp_events, pool_index);
2570   if (eth_mac_equal (event->new_mac, new_mac) &&
2571       sw_if_index == ntohl (event->sw_if_index))
2572     {
2573       return 1;
2574     }
2575
2576   clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
2577   event->sw_if_index = htonl (sw_if_index);
2578   return 0;
2579 }
2580
2581 static void
2582 vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
2583 {
2584   vpe_api_main_t *am = &vpe_api_main;
2585   vnet_main_t *vnm = vnet_get_main ();
2586   vl_api_want_ip4_arp_events_reply_t *rmp;
2587   int rv = 0;
2588
2589   if (mp->address == 0)
2590     {
2591       uword *p =
2592         hash_get (am->wc_ip4_arp_events_registration_hash, mp->client_index);
2593       vpe_client_registration_t *rp;
2594       if (p)
2595         {
2596           if (mp->enable_disable)
2597             {
2598               clib_warning ("pid %d: already enabled...", mp->pid);
2599               rv = VNET_API_ERROR_INVALID_REGISTRATION;
2600               goto reply;
2601             }
2602           else
2603             {
2604               rp =
2605                 pool_elt_at_index (am->wc_ip4_arp_events_registrations, p[0]);
2606               pool_put (am->wc_ip4_arp_events_registrations, rp);
2607               hash_unset (am->wc_ip4_arp_events_registration_hash,
2608                           mp->client_index);
2609               if (pool_elts (am->wc_ip4_arp_events_registrations) == 0)
2610                 wc_arp_set_publisher_node (~0, REPORT_MAX);
2611               goto reply;
2612             }
2613         }
2614       if (mp->enable_disable == 0)
2615         {
2616           clib_warning ("pid %d: already disabled...", mp->pid);
2617           rv = VNET_API_ERROR_INVALID_REGISTRATION;
2618           goto reply;
2619         }
2620       pool_get (am->wc_ip4_arp_events_registrations, rp);
2621       rp->client_index = mp->client_index;
2622       rp->client_pid = mp->pid;
2623       hash_set (am->wc_ip4_arp_events_registration_hash, rp->client_index,
2624                 rp - am->wc_ip4_arp_events_registrations);
2625       wc_arp_set_publisher_node (wc_arp_process_node.index, WC_ARP_REPORT);
2626       goto reply;
2627     }
2628
2629   if (mp->enable_disable)
2630     {
2631       vl_api_ip4_arp_event_t *event;
2632       pool_get (am->arp_events, event);
2633       rv = vnet_add_del_ip4_arp_change_event
2634         (vnm, arp_change_data_callback,
2635          mp->pid, &mp->address /* addr, in net byte order */ ,
2636          ip_resolver_process_node.index,
2637          IP4_ARP_EVENT, event - am->arp_events, 1 /* is_add */ );
2638
2639       if (rv)
2640         {
2641           pool_put (am->arp_events, event);
2642           goto reply;
2643         }
2644       memset (event, 0, sizeof (*event));
2645
2646       /* Python API expects events to have no context */
2647       event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
2648       event->client_index = mp->client_index;
2649       event->address = mp->address;
2650       event->pid = mp->pid;
2651       if (mp->address == 0)
2652         event->mac_ip = 1;
2653     }
2654   else
2655     {
2656       rv = vnet_add_del_ip4_arp_change_event
2657         (vnm, arp_change_delete_callback,
2658          mp->pid, &mp->address /* addr, in net byte order */ ,
2659          ip_resolver_process_node.index,
2660          IP4_ARP_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
2661     }
2662 reply:
2663   REPLY_MACRO (VL_API_WANT_IP4_ARP_EVENTS_REPLY);
2664 }
2665
2666 static clib_error_t *
2667 want_ip4_arp_events_reaper (u32 client_index)
2668 {
2669   vpe_client_registration_t *rp;
2670   vl_api_ip4_arp_event_t *event;
2671   u32 *to_delete, *event_id;
2672   vpe_api_main_t *am;
2673   vnet_main_t *vnm;
2674   uword *p;
2675
2676   am = &vpe_api_main;
2677   vnm = vnet_get_main ();
2678   to_delete = NULL;
2679
2680   /* clear out all of its pending resolutions */
2681   /* *INDENT-OFF* */
2682   pool_foreach(event, am->arp_events,
2683   ({
2684     if (event->client_index == client_index)
2685       {
2686         vec_add1(to_delete, event - am->arp_events);
2687       }
2688   }));
2689   /* *INDENT-ON* */
2690
2691   vec_foreach (event_id, to_delete)
2692   {
2693     event = pool_elt_at_index (am->arp_events, *event_id);
2694     vnet_add_del_ip4_arp_change_event
2695       (vnm, arp_change_delete_callback,
2696        event->pid, &event->address,
2697        ip_resolver_process_node.index, IP4_ARP_EVENT,
2698        ~0 /* pool index, notused */ , 0 /* is_add */ );
2699   }
2700   vec_free (to_delete);
2701
2702   /* remove from the registration hash */
2703   p = hash_get (am->wc_ip4_arp_events_registration_hash, client_index);
2704
2705   if (p)
2706     {
2707       rp = pool_elt_at_index (am->wc_ip4_arp_events_registrations, p[0]);
2708       pool_put (am->wc_ip4_arp_events_registrations, rp);
2709       hash_unset (am->wc_ip4_arp_events_registration_hash, client_index);
2710       if (pool_elts (am->wc_ip4_arp_events_registrations) == 0)
2711         wc_arp_set_publisher_node (~0, REPORT_MAX);
2712     }
2713   return (NULL);
2714 }
2715
2716 VL_MSG_API_REAPER_FUNCTION (want_ip4_arp_events_reaper);
2717
2718 static void
2719 vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
2720 {
2721   vpe_api_main_t *am = &vpe_api_main;
2722   vnet_main_t *vnm = vnet_get_main ();
2723   vl_api_want_ip6_nd_events_reply_t *rmp;
2724   int rv = 0;
2725
2726   if (ip6_address_is_zero ((ip6_address_t *) mp->address))
2727     {
2728       uword *p =
2729         hash_get (am->wc_ip6_nd_events_registration_hash, mp->client_index);
2730       vpe_client_registration_t *rp;
2731       if (p)
2732         {
2733           if (mp->enable_disable)
2734             {
2735               clib_warning ("pid %d: already enabled...", mp->pid);
2736               rv = VNET_API_ERROR_INVALID_REGISTRATION;
2737               goto reply;
2738             }
2739           else
2740             {
2741               rp =
2742                 pool_elt_at_index (am->wc_ip6_nd_events_registrations, p[0]);
2743               pool_put (am->wc_ip6_nd_events_registrations, rp);
2744               hash_unset (am->wc_ip6_nd_events_registration_hash,
2745                           mp->client_index);
2746               if (pool_elts (am->wc_ip6_nd_events_registrations) == 0)
2747                 wc_nd_set_publisher_node (~0, REPORT_MAX);
2748               goto reply;
2749             }
2750         }
2751       if (mp->enable_disable == 0)
2752         {
2753           clib_warning ("pid %d: already disabled...", mp->pid);
2754           rv = VNET_API_ERROR_INVALID_REGISTRATION;
2755           goto reply;
2756         }
2757       pool_get (am->wc_ip6_nd_events_registrations, rp);
2758       rp->client_index = mp->client_index;
2759       rp->client_pid = mp->pid;
2760       hash_set (am->wc_ip6_nd_events_registration_hash, rp->client_index,
2761                 rp - am->wc_ip6_nd_events_registrations);
2762       wc_nd_set_publisher_node (wc_arp_process_node.index, WC_ND_REPORT);
2763       goto reply;
2764     }
2765
2766   if (mp->enable_disable)
2767     {
2768       vl_api_ip6_nd_event_t *event;
2769       pool_get (am->nd_events, event);
2770
2771       rv = vnet_add_del_ip6_nd_change_event
2772         (vnm, nd_change_data_callback,
2773          mp->pid, mp->address /* addr, in net byte order */ ,
2774          ip_resolver_process_node.index,
2775          IP6_ND_EVENT, event - am->nd_events, 1 /* is_add */ );
2776
2777       if (rv)
2778         {
2779           pool_put (am->nd_events, event);
2780           goto reply;
2781         }
2782       memset (event, 0, sizeof (*event));
2783
2784       event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT);
2785       event->client_index = mp->client_index;
2786       clib_memcpy (event->address, mp->address, sizeof event->address);
2787       event->pid = mp->pid;
2788     }
2789   else
2790     {
2791       rv = vnet_add_del_ip6_nd_change_event
2792         (vnm, nd_change_delete_callback,
2793          mp->pid, mp->address /* addr, in net byte order */ ,
2794          ip_resolver_process_node.index,
2795          IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
2796     }
2797 reply:
2798   REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY);
2799 }
2800
2801 static clib_error_t *
2802 want_ip6_nd_events_reaper (u32 client_index)
2803 {
2804
2805   vpe_client_registration_t *rp;
2806   vl_api_ip6_nd_event_t *event;
2807   u32 *to_delete, *event_id;
2808   vpe_api_main_t *am;
2809   vnet_main_t *vnm;
2810   uword *p;
2811
2812   am = &vpe_api_main;
2813   vnm = vnet_get_main ();
2814   to_delete = NULL;
2815
2816   /* clear out all of its pending resolutions */
2817   /* *INDENT-OFF* */
2818   pool_foreach(event, am->nd_events,
2819   ({
2820     if (event->client_index == client_index)
2821       {
2822         vec_add1(to_delete, event - am->nd_events);
2823       }
2824   }));
2825   /* *INDENT-ON* */
2826
2827   vec_foreach (event_id, to_delete)
2828   {
2829     event = pool_elt_at_index (am->nd_events, *event_id);
2830     vnet_add_del_ip6_nd_change_event
2831       (vnm, nd_change_delete_callback,
2832        event->pid, &event->address,
2833        ip_resolver_process_node.index, IP6_ND_EVENT,
2834        ~0 /* pool index, notused */ , 0 /* is_add */ );
2835   }
2836   vec_free (to_delete);
2837
2838   /* remove from the registration hash */
2839   p = hash_get (am->wc_ip6_nd_events_registration_hash, client_index);
2840
2841   if (p)
2842     {
2843       rp = pool_elt_at_index (am->wc_ip6_nd_events_registrations, p[0]);
2844       pool_put (am->wc_ip6_nd_events_registrations, rp);
2845       hash_unset (am->wc_ip6_nd_events_registration_hash, client_index);
2846       if (pool_elts (am->wc_ip6_nd_events_registrations) == 0)
2847         wc_nd_set_publisher_node (~0, REPORT_MAX);
2848     }
2849   return (NULL);
2850 }
2851
2852 VL_MSG_API_REAPER_FUNCTION (want_ip6_nd_events_reaper);
2853
2854 static void
2855 vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
2856 {
2857   vpe_api_main_t *am = &vpe_api_main;
2858   vl_api_want_ip6_ra_events_reply_t *rmp;
2859   int rv = 0;
2860
2861   uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
2862   vpe_client_registration_t *rp;
2863   if (p)
2864     {
2865       if (mp->enable_disable)
2866         {
2867           clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
2868           rv = VNET_API_ERROR_INVALID_REGISTRATION;
2869           goto reply;
2870         }
2871       else
2872         {
2873           rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
2874           pool_put (am->ip6_ra_events_registrations, rp);
2875           hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
2876           goto reply;
2877         }
2878     }
2879   if (mp->enable_disable == 0)
2880     {
2881       clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
2882       rv = VNET_API_ERROR_INVALID_REGISTRATION;
2883       goto reply;
2884     }
2885   pool_get (am->ip6_ra_events_registrations, rp);
2886   rp->client_index = mp->client_index;
2887   rp->client_pid = ntohl (mp->pid);
2888   hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
2889             rp - am->ip6_ra_events_registrations);
2890
2891 reply:
2892   REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
2893 }
2894
2895 static clib_error_t *
2896 want_ip6_ra_events_reaper (u32 client_index)
2897 {
2898   vpe_api_main_t *am = &vpe_api_main;
2899   vpe_client_registration_t *rp;
2900   uword *p;
2901
2902   p = hash_get (am->ip6_ra_events_registration_hash, client_index);
2903
2904   if (p)
2905     {
2906       rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
2907       pool_put (am->ip6_ra_events_registrations, rp);
2908       hash_unset (am->ip6_ra_events_registration_hash, client_index);
2909     }
2910   return (NULL);
2911 }
2912
2913 VL_MSG_API_REAPER_FUNCTION (want_ip6_ra_events_reaper);
2914
2915 static void
2916 vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp)
2917 {
2918   vl_api_proxy_arp_add_del_reply_t *rmp;
2919   u32 fib_index;
2920   int rv;
2921   ip4_main_t *im = &ip4_main;
2922   uword *p;
2923
2924   stats_dslock_with_hint (1 /* release hint */ , 6 /* tag */ );
2925
2926   p = hash_get (im->fib_index_by_table_id, ntohl (mp->proxy.vrf_id));
2927
2928   if (!p)
2929     {
2930       rv = VNET_API_ERROR_NO_SUCH_FIB;
2931       goto out;
2932     }
2933
2934   fib_index = p[0];
2935
2936   rv = vnet_proxy_arp_add_del ((ip4_address_t *) mp->proxy.low_address,
2937                                (ip4_address_t *) mp->proxy.hi_address,
2938                                fib_index, mp->is_add == 0);
2939
2940 out:
2941   stats_dsunlock ();
2942   REPLY_MACRO (VL_API_PROXY_ARP_ADD_DEL_REPLY);
2943 }
2944
2945 typedef struct proxy_arp_walk_ctx_t_
2946 {
2947   vl_api_registration_t *reg;
2948   u32 context;
2949 } proxy_arp_walk_ctx_t;
2950
2951 static walk_rc_t
2952 send_proxy_arp_details (const ip4_address_t * lo_addr,
2953                         const ip4_address_t * hi_addr,
2954                         u32 fib_index, void *data)
2955 {
2956   vl_api_proxy_arp_details_t *mp;
2957   proxy_arp_walk_ctx_t *ctx;
2958
2959   ctx = data;
2960
2961   mp = vl_msg_api_alloc (sizeof (*mp));
2962   memset (mp, 0, sizeof (*mp));
2963   mp->_vl_msg_id = ntohs (VL_API_PROXY_ARP_DETAILS);
2964   mp->context = ctx->context;
2965   mp->proxy.vrf_id = htonl (fib_index);
2966   clib_memcpy (mp->proxy.low_address, lo_addr,
2967                sizeof (mp->proxy.low_address));
2968   clib_memcpy (mp->proxy.hi_address, hi_addr, sizeof (mp->proxy.hi_address));
2969
2970   vl_api_send_msg (ctx->reg, (u8 *) mp);
2971
2972   return (WALK_CONTINUE);
2973 }
2974
2975 static void
2976 vl_api_proxy_arp_dump_t_handler (vl_api_proxy_arp_dump_t * mp)
2977 {
2978   vl_api_registration_t *reg;
2979
2980   reg = vl_api_client_index_to_registration (mp->client_index);
2981   if (!reg)
2982     return;
2983
2984   proxy_arp_walk_ctx_t wctx = {
2985     .reg = reg,
2986     .context = mp->context,
2987   };
2988
2989   proxy_arp_walk (send_proxy_arp_details, &wctx);
2990 }
2991
2992 static walk_rc_t
2993 send_proxy_arp_intfc_details (vnet_main_t * vnm,
2994                               vnet_sw_interface_t * si, void *data)
2995 {
2996   vl_api_proxy_arp_intfc_details_t *mp;
2997   proxy_arp_walk_ctx_t *ctx;
2998
2999   if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
3000     return (WALK_CONTINUE);
3001
3002   ctx = data;
3003
3004   mp = vl_msg_api_alloc (sizeof (*mp));
3005   memset (mp, 0, sizeof (*mp));
3006   mp->_vl_msg_id = ntohs (VL_API_PROXY_ARP_INTFC_DETAILS);
3007   mp->context = ctx->context;
3008   mp->sw_if_index = htonl (si->sw_if_index);
3009
3010   vl_api_send_msg (ctx->reg, (u8 *) mp);
3011
3012   return (WALK_CONTINUE);
3013 }
3014
3015 static void
3016 vl_api_proxy_arp_intfc_dump_t_handler (vl_api_proxy_arp_intfc_dump_t * mp)
3017 {
3018   vl_api_registration_t *reg;
3019
3020   reg = vl_api_client_index_to_registration (mp->client_index);
3021   if (!reg)
3022     return;
3023
3024   proxy_arp_walk_ctx_t wctx = {
3025     .reg = reg,
3026     .context = mp->context,
3027   };
3028
3029   vnet_sw_interface_walk (vnet_get_main (),
3030                           send_proxy_arp_intfc_details, &wctx);
3031 }
3032
3033 static void
3034   vl_api_proxy_arp_intfc_enable_disable_t_handler
3035   (vl_api_proxy_arp_intfc_enable_disable_t * mp)
3036 {
3037   int rv = 0;
3038   vnet_main_t *vnm = vnet_get_main ();
3039   vl_api_proxy_arp_intfc_enable_disable_reply_t *rmp;
3040
3041   VALIDATE_SW_IF_INDEX (mp);
3042
3043   vnet_sw_interface_t *si =
3044     vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
3045
3046   ASSERT (si);
3047
3048   if (mp->enable_disable)
3049     si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
3050   else
3051     si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
3052
3053   BAD_SW_IF_INDEX_LABEL;
3054
3055   REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
3056 }
3057
3058 static void
3059 vl_api_ip_probe_neighbor_t_handler (vl_api_ip_probe_neighbor_t * mp)
3060 {
3061   int rv = 0;
3062   vlib_main_t *vm = vlib_get_main ();
3063   vl_api_ip_probe_neighbor_reply_t *rmp;
3064   clib_error_t *error;
3065
3066   VALIDATE_SW_IF_INDEX (mp);
3067
3068   u32 sw_if_index = ntohl (mp->sw_if_index);
3069
3070   if (mp->is_ipv6)
3071     error = ip6_probe_neighbor (vm, (ip6_address_t *) mp->dst_address,
3072                                 sw_if_index, 0);
3073   else
3074     error = ip4_probe_neighbor (vm, (ip4_address_t *) mp->dst_address,
3075                                 sw_if_index, 0);
3076
3077   if (error)
3078     {
3079       clib_error_report (error);
3080       rv = clib_error_get_code (error);
3081     }
3082
3083   BAD_SW_IF_INDEX_LABEL;
3084
3085   REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
3086 }
3087
3088 static void
3089   vl_api_ip_scan_neighbor_enable_disable_t_handler
3090   (vl_api_ip_scan_neighbor_enable_disable_t * mp)
3091 {
3092   int rv = 0;
3093   vl_api_ip_scan_neighbor_enable_disable_reply_t *rmp;
3094   ip_neighbor_scan_arg_t arg;
3095
3096   arg.mode = mp->mode;
3097   arg.scan_interval = mp->scan_interval;
3098   arg.max_proc_time = mp->max_proc_time;
3099   arg.max_update = mp->max_update;
3100   arg.scan_int_delay = mp->scan_int_delay;
3101   arg.stale_threshold = mp->stale_threshold;
3102   ip_neighbor_scan_enable_disable (&arg);
3103
3104   REPLY_MACRO (VL_API_IP_SCAN_NEIGHBOR_ENABLE_DISABLE_REPLY);
3105 }
3106
3107 static int
3108 ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
3109 {
3110   vnet_main_t *vnm = vnet_get_main ();
3111   vnet_interface_main_t *im = &vnm->interface_main;
3112   ip4_main_t *im4 = &ip4_main;
3113   static u32 *sw_if_indices_to_shut;
3114   fib_table_t *fib_table;
3115   ip4_fib_t *fib;
3116   u32 sw_if_index;
3117   int i;
3118   int rv = VNET_API_ERROR_NO_SUCH_FIB;
3119   u32 target_fib_id = ntohl (mp->vrf_id);
3120
3121   stats_dslock_with_hint (1 /* release hint */ , 8 /* tag */ );
3122
3123   /* *INDENT-OFF* */
3124   pool_foreach (fib_table, im4->fibs,
3125   ({
3126     vnet_sw_interface_t * si;
3127
3128     fib = pool_elt_at_index (im4->v4_fibs, fib_table->ft_index);
3129
3130     if (fib->table_id != target_fib_id)
3131       continue;
3132
3133     /* remove any mpls encap/decap labels */
3134     mpls_fib_reset_labels (fib->table_id);
3135
3136     /* remove any proxy arps in this fib */
3137     vnet_proxy_arp_fib_reset (fib->table_id);
3138
3139     /* Set the flow hash for this fib to the default */
3140     vnet_set_ip4_flow_hash (fib->table_id, IP_FLOW_HASH_DEFAULT);
3141
3142     vec_reset_length (sw_if_indices_to_shut);
3143
3144     /* Shut down interfaces in this FIB / clean out intfc routes */
3145     pool_foreach (si, im->sw_interfaces,
3146     ({
3147       u32 sw_if_index = si->sw_if_index;
3148
3149       if (sw_if_index < vec_len (im4->fib_index_by_sw_if_index)
3150           && (im4->fib_index_by_sw_if_index[si->sw_if_index] ==
3151               fib->index))
3152         vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
3153     }));
3154
3155     for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
3156       sw_if_index = sw_if_indices_to_shut[i];
3157
3158       u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
3159       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3160       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
3161     }
3162
3163     fib_table_flush(fib->index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
3164
3165     rv = 0;
3166     break;
3167     })); /* pool_foreach (fib) */
3168     /* *INDENT-ON* */
3169
3170   stats_dsunlock ();
3171   return rv;
3172 }
3173
3174 static int
3175 ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
3176 {
3177   vnet_main_t *vnm = vnet_get_main ();
3178   vnet_interface_main_t *im = &vnm->interface_main;
3179   ip6_main_t *im6 = &ip6_main;
3180   static u32 *sw_if_indices_to_shut;
3181   fib_table_t *fib_table;
3182   ip6_fib_t *fib;
3183   u32 sw_if_index;
3184   int i;
3185   int rv = VNET_API_ERROR_NO_SUCH_FIB;
3186   u32 target_fib_id = ntohl (mp->vrf_id);
3187
3188   stats_dslock_with_hint (1 /* release hint */ , 9 /* tag */ );
3189
3190   /* *INDENT-OFF* */
3191   pool_foreach (fib_table, im6->fibs,
3192   ({
3193     vnet_sw_interface_t * si;
3194
3195     fib = pool_elt_at_index (im6->v6_fibs, fib_table->ft_index);
3196
3197     if (fib->table_id != target_fib_id)
3198       continue;
3199
3200     vec_reset_length (sw_if_indices_to_shut);
3201
3202     /* Set the flow hash for this fib to the default */
3203     vnet_set_ip6_flow_hash (fib->table_id, IP_FLOW_HASH_DEFAULT);
3204
3205     /* Shut down interfaces in this FIB / clean out intfc routes */
3206     pool_foreach (si, im->sw_interfaces,
3207     ({
3208       if (im6->fib_index_by_sw_if_index[si->sw_if_index] ==
3209           fib->index)
3210         vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
3211     }));
3212
3213     for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
3214       sw_if_index = sw_if_indices_to_shut[i];
3215
3216       u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
3217       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
3218       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
3219     }
3220
3221     fib_table_flush(fib->index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
3222
3223     rv = 0;
3224     break;
3225   })); /* pool_foreach (fib) */
3226   /* *INDENT-ON* */
3227
3228   stats_dsunlock ();
3229   return rv;
3230 }
3231
3232 static void
3233 vl_api_reset_fib_t_handler (vl_api_reset_fib_t * mp)
3234 {
3235   int rv;
3236   vl_api_reset_fib_reply_t *rmp;
3237
3238   if (mp->is_ipv6)
3239     rv = ip6_reset_fib_t_handler (mp);
3240   else
3241     rv = ip4_reset_fib_t_handler (mp);
3242
3243   REPLY_MACRO (VL_API_RESET_FIB_REPLY);
3244 }
3245
3246 static void
3247 vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp)
3248 {
3249   int rv;
3250   vl_api_set_arp_neighbor_limit_reply_t *rmp;
3251   vnet_main_t *vnm = vnet_get_main ();
3252   clib_error_t *error;
3253
3254   vnm->api_errno = 0;
3255
3256   if (mp->is_ipv6)
3257     error = ip6_set_neighbor_limit (ntohl (mp->arp_neighbor_limit));
3258   else
3259     error = ip4_set_arp_limit (ntohl (mp->arp_neighbor_limit));
3260
3261   if (error)
3262     {
3263       clib_error_report (error);
3264       rv = VNET_API_ERROR_UNSPECIFIED;
3265     }
3266   else
3267     {
3268       rv = vnm->api_errno;
3269     }
3270
3271   REPLY_MACRO (VL_API_SET_ARP_NEIGHBOR_LIMIT_REPLY);
3272 }
3273
3274 void
3275 vl_api_ip_reassembly_set_t_handler (vl_api_ip_reassembly_set_t * mp)
3276 {
3277   vl_api_ip_reassembly_set_reply_t *rmp;
3278   int rv = 0;
3279   if (mp->is_ip6)
3280     {
3281       rv = ip6_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
3282                           clib_net_to_host_u32 (mp->max_reassemblies),
3283                           clib_net_to_host_u32 (mp->expire_walk_interval_ms));
3284     }
3285   else
3286     {
3287       rv = ip4_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
3288                           clib_net_to_host_u32 (mp->max_reassemblies),
3289                           clib_net_to_host_u32 (mp->expire_walk_interval_ms));
3290     }
3291
3292   REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
3293 }
3294
3295 void
3296 vl_api_ip_reassembly_get_t_handler (vl_api_ip_reassembly_get_t * mp)
3297 {
3298   unix_shared_memory_queue_t *q;
3299
3300   q = vl_api_client_index_to_input_queue (mp->client_index);
3301
3302   if (q == 0)
3303     return;
3304
3305   vl_api_ip_reassembly_get_reply_t *rmp = vl_msg_api_alloc (sizeof (*rmp));
3306   memset (rmp, 0, sizeof (*rmp));
3307   rmp->_vl_msg_id = ntohs (VL_API_IP_REASSEMBLY_GET_REPLY);
3308   rmp->context = mp->context;
3309   rmp->retval = 0;
3310   if (mp->is_ip6)
3311     {
3312       rmp->is_ip6 = 1;
3313       ip6_reass_get (&rmp->timeout_ms, &rmp->max_reassemblies,
3314                      &rmp->expire_walk_interval_ms);
3315     }
3316   else
3317     {
3318       rmp->is_ip6 = 0;
3319       ip4_reass_get (&rmp->timeout_ms, &rmp->max_reassemblies,
3320                      &rmp->expire_walk_interval_ms);
3321     }
3322   rmp->timeout_ms = clib_host_to_net_u32 (rmp->timeout_ms);
3323   rmp->max_reassemblies = clib_host_to_net_u32 (rmp->max_reassemblies);
3324   rmp->expire_walk_interval_ms =
3325     clib_host_to_net_u32 (rmp->expire_walk_interval_ms);
3326   vl_msg_api_send_shmem (q, (u8 *) & rmp);
3327 }
3328
3329 void
3330   vl_api_ip_reassembly_enable_disable_t_handler
3331   (vl_api_ip_reassembly_enable_disable_t * mp)
3332 {
3333   vl_api_ip_reassembly_enable_disable_reply_t *rmp;
3334   int rv = 0;
3335   rv = ip4_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
3336                                  mp->enable_ip4);
3337   if (0 == rv)
3338     {
3339       rv = ip6_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
3340                                      mp->enable_ip6);
3341     }
3342
3343   REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
3344 }
3345
3346 #define vl_msg_name_crc_list
3347 #include <vnet/ip/ip.api.h>
3348 #undef vl_msg_name_crc_list
3349
3350 static void
3351 setup_message_id_table (api_main_t * am)
3352 {
3353 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
3354   foreach_vl_msg_name_crc_ip;
3355 #undef _
3356 }
3357
3358 static clib_error_t *
3359 ip_api_hookup (vlib_main_t * vm)
3360 {
3361   api_main_t *am = &api_main;
3362
3363 #define _(N,n)                                                  \
3364     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
3365                            vl_api_##n##_t_handler,              \
3366                            vl_noop_handler,                     \
3367                            vl_api_##n##_t_endian,               \
3368                            vl_api_##n##_t_print,                \
3369                            sizeof(vl_api_##n##_t), 1);
3370   foreach_ip_api_msg;
3371 #undef _
3372
3373   /*
3374    * Set up the (msg_name, crc, message-id) table
3375    */
3376   setup_message_id_table (am);
3377
3378   ra_set_publisher_node (wc_arp_process_node.index, RA_REPORT);
3379
3380   return 0;
3381 }
3382
3383 VLIB_API_INIT_FUNCTION (ip_api_hookup);
3384
3385 /*
3386  * fd.io coding-style-patch-verification: ON
3387  *
3388  * Local Variables:
3389  * eval: (c-set-style "gnu")
3390  * End:
3391  */