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