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