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