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