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