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