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