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