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