IP address dump - don't send subnets for unnumbered interfaces
[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       /* Do not send subnet details of the IP-interface for
1399        * unnumbered interfaces. otherwise listening clients
1400        * will be confused that the subnet is applied on more
1401        * than one interface */
1402       foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
1403       ({
1404         r6 = ip_interface_address_get_address (lm6, ia);
1405         u16 prefix_length = ia->address_length;
1406         send_ip_address_details(am, reg, (u8*)r6, prefix_length,
1407                                 sw_if_index, 1, mp->context);
1408       }));
1409       /* *INDENT-ON* */
1410     }
1411   else
1412     {
1413       /* *INDENT-OFF* */
1414       foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1415       ({
1416         r4 = ip_interface_address_get_address (lm4, ia);
1417         u16 prefix_length = ia->address_length;
1418         send_ip_address_details(am, reg, (u8*)r4, prefix_length,
1419                                 sw_if_index, 0, mp->context);
1420       }));
1421       /* *INDENT-ON* */
1422     }
1423   BAD_SW_IF_INDEX_LABEL;
1424 }
1425
1426 static void
1427 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
1428 {
1429   vpe_api_main_t *am = &vpe_api_main;
1430   vnet_main_t *vnm = vnet_get_main ();
1431   vlib_main_t *vm = vlib_get_main ();
1432   vnet_interface_main_t *im = &vnm->interface_main;
1433   vl_api_registration_t *reg;
1434   vnet_sw_interface_t *si, *sorted_sis;
1435   u32 sw_if_index = ~0;
1436
1437   reg = vl_api_client_index_to_registration (mp->client_index);
1438   if (!reg)
1439     return;
1440
1441   /* Gather interfaces. */
1442   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1443   _vec_len (sorted_sis) = 0;
1444   /* *INDENT-OFF* */
1445   pool_foreach (si, im->sw_interfaces,
1446   ({
1447     vec_add1 (sorted_sis, si[0]);
1448   }));
1449   /* *INDENT-ON* */
1450
1451   vec_foreach (si, sorted_sis)
1452   {
1453     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1454       {
1455         if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index))
1456           {
1457             continue;
1458           }
1459         sw_if_index = si->sw_if_index;
1460         send_ip_details (am, reg, sw_if_index, mp->is_ipv6, mp->context);
1461       }
1462   }
1463 }
1464
1465 static void
1466 set_ip6_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1467 {
1468   vl_api_set_ip_flow_hash_reply_t *rmp;
1469   int rv;
1470   u32 table_id;
1471   flow_hash_config_t flow_hash_config = 0;
1472
1473   table_id = ntohl (mp->vrf_id);
1474
1475 #define _(a,b) if (mp->a) flow_hash_config |= b;
1476   foreach_flow_hash_bit;
1477 #undef _
1478
1479   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
1480
1481   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1482 }
1483
1484 static void
1485 set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1486 {
1487   vl_api_set_ip_flow_hash_reply_t *rmp;
1488   int rv;
1489   u32 table_id;
1490   flow_hash_config_t flow_hash_config = 0;
1491
1492   table_id = ntohl (mp->vrf_id);
1493
1494 #define _(a,b) if (mp->a) flow_hash_config |= b;
1495   foreach_flow_hash_bit;
1496 #undef _
1497
1498   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
1499
1500   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1501 }
1502
1503
1504 static void
1505 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t * mp)
1506 {
1507   if (mp->is_ipv6 == 0)
1508     set_ip4_flow_hash (mp);
1509   else
1510     set_ip6_flow_hash (mp);
1511 }
1512
1513 static void
1514   vl_api_sw_interface_ip6nd_ra_config_t_handler
1515   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
1516 {
1517   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
1518   vlib_main_t *vm = vlib_get_main ();
1519   int rv = 0;
1520   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
1521     default_router;
1522
1523   is_no = mp->is_no == 1;
1524   suppress = mp->suppress == 1;
1525   managed = mp->managed == 1;
1526   other = mp->other == 1;
1527   ll_option = mp->ll_option == 1;
1528   send_unicast = mp->send_unicast == 1;
1529   cease = mp->cease == 1;
1530   default_router = mp->default_router == 1;
1531
1532   VALIDATE_SW_IF_INDEX (mp);
1533
1534   rv = ip6_neighbor_ra_config (vm, ntohl (mp->sw_if_index),
1535                                suppress, managed, other,
1536                                ll_option, send_unicast, cease,
1537                                default_router, ntohl (mp->lifetime),
1538                                ntohl (mp->initial_count),
1539                                ntohl (mp->initial_interval),
1540                                ntohl (mp->max_interval),
1541                                ntohl (mp->min_interval), is_no);
1542
1543   BAD_SW_IF_INDEX_LABEL;
1544
1545   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
1546 }
1547
1548 static void
1549   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
1550   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
1551 {
1552   vlib_main_t *vm = vlib_get_main ();
1553   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
1554   int rv = 0;
1555   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
1556
1557   VALIDATE_SW_IF_INDEX (mp);
1558
1559   is_no = mp->is_no == 1;
1560   use_default = mp->use_default == 1;
1561   no_advertise = mp->no_advertise == 1;
1562   off_link = mp->off_link == 1;
1563   no_autoconfig = mp->no_autoconfig == 1;
1564   no_onlink = mp->no_onlink == 1;
1565
1566   rv = ip6_neighbor_ra_prefix (vm, ntohl (mp->sw_if_index),
1567                                (ip6_address_t *) mp->address,
1568                                mp->address_length, use_default,
1569                                ntohl (mp->val_lifetime),
1570                                ntohl (mp->pref_lifetime), no_advertise,
1571                                off_link, no_autoconfig, no_onlink, is_no);
1572
1573   BAD_SW_IF_INDEX_LABEL;
1574   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
1575 }
1576
1577 static void
1578 send_ip6nd_proxy_details (vl_api_registration_t * reg,
1579                           u32 context,
1580                           const ip46_address_t * addr, u32 sw_if_index)
1581 {
1582   vl_api_ip6nd_proxy_details_t *mp;
1583
1584   mp = vl_msg_api_alloc (sizeof (*mp));
1585   memset (mp, 0, sizeof (*mp));
1586   mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
1587   mp->context = context;
1588   mp->sw_if_index = htonl (sw_if_index);
1589   memcpy (mp->address, addr, 16);
1590
1591   vl_api_send_msg (reg, (u8 *) mp);
1592 }
1593
1594 typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
1595 {
1596   u32 *indices;
1597 } api_ip6nd_proxy_fib_table_walk_ctx_t;
1598
1599 static fib_table_walk_rc_t
1600 api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
1601 {
1602   api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
1603
1604   if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
1605     {
1606       vec_add1 (ctx->indices, fei);
1607     }
1608
1609   return (FIB_TABLE_WALK_CONTINUE);
1610 }
1611
1612 static void
1613 vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
1614 {
1615   ip6_main_t *im6 = &ip6_main;
1616   fib_table_t *fib_table;
1617   api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
1618     .indices = NULL,
1619   };
1620   fib_node_index_t *feip;
1621   fib_prefix_t pfx;
1622   vl_api_registration_t *reg;
1623
1624   reg = vl_api_client_index_to_registration (mp->client_index);
1625   if (!reg)
1626     return;
1627
1628   /* *INDENT-OFF* */
1629   pool_foreach (fib_table, im6->fibs,
1630   ({
1631     fib_table_walk(fib_table->ft_index,
1632                    FIB_PROTOCOL_IP6,
1633                    api_ip6nd_proxy_fib_table_walk,
1634                    &ctx);
1635   }));
1636   /* *INDENT-ON* */
1637
1638   vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
1639
1640   vec_foreach (feip, ctx.indices)
1641   {
1642     fib_entry_get_prefix (*feip, &pfx);
1643
1644     send_ip6nd_proxy_details (reg,
1645                               mp->context,
1646                               &pfx.fp_addr,
1647                               fib_entry_get_resolving_interface (*feip));
1648   }
1649
1650   vec_free (ctx.indices);
1651 }
1652
1653 static void
1654 vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
1655 {
1656   vl_api_ip6nd_proxy_add_del_reply_t *rmp;
1657   int rv = 0;
1658
1659   VALIDATE_SW_IF_INDEX (mp);
1660
1661   rv = ip6_neighbor_proxy_add_del (ntohl (mp->sw_if_index),
1662                                    (ip6_address_t *) mp->address, mp->is_del);
1663
1664   BAD_SW_IF_INDEX_LABEL;
1665   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
1666 }
1667
1668 static void
1669   vl_api_ip6nd_send_router_solicitation_t_handler
1670   (vl_api_ip6nd_send_router_solicitation_t * mp)
1671 {
1672   vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
1673   icmp6_send_router_solicitation_params_t params;
1674   vlib_main_t *vm = vlib_get_main ();
1675   int rv = 0;
1676
1677   VALIDATE_SW_IF_INDEX (mp);
1678
1679   BAD_SW_IF_INDEX_LABEL;
1680   REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
1681
1682   if (rv != 0)
1683     return;
1684
1685   params.irt = ntohl (mp->irt);
1686   params.mrt = ntohl (mp->mrt);
1687   params.mrc = ntohl (mp->mrc);
1688   params.mrd = ntohl (mp->mrd);
1689
1690   icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
1691                                   &params);
1692 }
1693
1694 static void
1695   vl_api_sw_interface_ip6_enable_disable_t_handler
1696   (vl_api_sw_interface_ip6_enable_disable_t * mp)
1697 {
1698   vlib_main_t *vm = vlib_get_main ();
1699   vl_api_sw_interface_ip6_enable_disable_reply_t *rmp;
1700   vnet_main_t *vnm = vnet_get_main ();
1701   int rv = 0;
1702   clib_error_t *error;
1703
1704   vnm->api_errno = 0;
1705
1706   VALIDATE_SW_IF_INDEX (mp);
1707
1708   error =
1709     (mp->enable == 1) ? enable_ip6_interface (vm,
1710                                               ntohl (mp->sw_if_index)) :
1711     disable_ip6_interface (vm, ntohl (mp->sw_if_index));
1712
1713   if (error)
1714     {
1715       clib_error_report (error);
1716       rv = VNET_API_ERROR_UNSPECIFIED;
1717     }
1718   else
1719     {
1720       rv = vnm->api_errno;
1721     }
1722
1723   BAD_SW_IF_INDEX_LABEL;
1724
1725   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
1726 }
1727
1728 static void
1729   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1730   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1731 {
1732   vlib_main_t *vm = vlib_get_main ();
1733   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1734   int rv = 0;
1735   clib_error_t *error;
1736   vnet_main_t *vnm = vnet_get_main ();
1737
1738   vnm->api_errno = 0;
1739
1740   VALIDATE_SW_IF_INDEX (mp);
1741
1742   error = set_ip6_link_local_address (vm,
1743                                       ntohl (mp->sw_if_index),
1744                                       (ip6_address_t *) mp->address);
1745   if (error)
1746     {
1747       clib_error_report (error);
1748       rv = VNET_API_ERROR_UNSPECIFIED;
1749     }
1750   else
1751     {
1752       rv = vnm->api_errno;
1753     }
1754
1755   BAD_SW_IF_INDEX_LABEL;
1756
1757   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1758 }
1759
1760 void
1761 vl_mfib_signal_send_one (vl_api_registration_t * reg,
1762                          u32 context, const mfib_signal_t * mfs)
1763 {
1764   vl_api_mfib_signal_details_t *mp;
1765   mfib_prefix_t prefix;
1766   mfib_table_t *mfib;
1767   mfib_itf_t *mfi;
1768
1769   mp = vl_msg_api_alloc (sizeof (*mp));
1770
1771   memset (mp, 0, sizeof (*mp));
1772   mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS);
1773   mp->context = context;
1774
1775   mfi = mfib_itf_get (mfs->mfs_itf);
1776   mfib_entry_get_prefix (mfs->mfs_entry, &prefix);
1777   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1778                          prefix.fp_proto);
1779   mp->table_id = ntohl (mfib->mft_table_id);
1780   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1781
1782   if (FIB_PROTOCOL_IP4 == prefix.fp_proto)
1783     {
1784       mp->grp_address_len = ntohs (prefix.fp_len);
1785
1786       memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4);
1787       if (prefix.fp_len > 32)
1788         {
1789           memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4);
1790         }
1791     }
1792   else
1793     {
1794       mp->grp_address_len = ntohs (prefix.fp_len);
1795
1796       ASSERT (0);
1797     }
1798
1799   if (0 != mfs->mfs_buffer_len)
1800     {
1801       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1802
1803       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1804     }
1805   else
1806     {
1807       mp->ip_packet_len = 0;
1808     }
1809
1810   vl_api_send_msg (reg, (u8 *) mp);
1811 }
1812
1813 static void
1814 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1815 {
1816   vl_api_registration_t *reg;
1817
1818   reg = vl_api_client_index_to_registration (mp->client_index);
1819   if (!reg)
1820     return;
1821
1822   while (vl_api_can_send_msg (reg) && mfib_signal_send_one (reg, mp->context))
1823     ;
1824 }
1825
1826 static void
1827   vl_api_ip_container_proxy_add_del_t_handler
1828   (vl_api_ip_container_proxy_add_del_t * mp)
1829 {
1830   vl_api_ip_container_proxy_add_del_reply_t *rmp;
1831   vnet_ip_container_proxy_args_t args;
1832   int rv = 0;
1833   clib_error_t *error;
1834
1835   memset (&args, 0, sizeof (args));
1836   ip_set (&args.prefix.fp_addr, mp->ip, mp->is_ip4);
1837   args.prefix.fp_len = mp->plen ? mp->plen : (mp->is_ip4 ? 32 : 128);
1838   args.sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
1839   args.is_add = mp->is_add;
1840   if ((error = vnet_ip_container_proxy_add_del (&args)))
1841     {
1842       rv = clib_error_get_code (error);
1843       clib_error_report (error);
1844     }
1845
1846   REPLY_MACRO (VL_API_IP_CONTAINER_PROXY_ADD_DEL_REPLY);
1847 }
1848
1849 static void
1850 vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
1851 {
1852   int rv = 0;
1853   vl_api_ioam_enable_reply_t *rmp;
1854   clib_error_t *error;
1855
1856   /* Ignoring the profile id as currently a single profile
1857    * is supported */
1858   error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable,
1859                            mp->seqno, mp->analyse);
1860   if (error)
1861     {
1862       clib_error_report (error);
1863       rv = clib_error_get_code (error);
1864     }
1865
1866   REPLY_MACRO (VL_API_IOAM_ENABLE_REPLY);
1867 }
1868
1869 static void
1870 vl_api_ioam_disable_t_handler (vl_api_ioam_disable_t * mp)
1871 {
1872   int rv = 0;
1873   vl_api_ioam_disable_reply_t *rmp;
1874   clib_error_t *error;
1875
1876   error = clear_ioam_rewrite_fn ();
1877   if (error)
1878     {
1879       clib_error_report (error);
1880       rv = clib_error_get_code (error);
1881     }
1882
1883   REPLY_MACRO (VL_API_IOAM_DISABLE_REPLY);
1884 }
1885
1886 static void
1887   vl_api_ip_source_and_port_range_check_add_del_t_handler
1888   (vl_api_ip_source_and_port_range_check_add_del_t * mp)
1889 {
1890   vl_api_ip_source_and_port_range_check_add_del_reply_t *rmp;
1891   int rv = 0;
1892
1893   u8 is_ipv6 = mp->is_ipv6;
1894   u8 is_add = mp->is_add;
1895   u8 mask_length = mp->mask_length;
1896   ip4_address_t ip4_addr;
1897   ip6_address_t ip6_addr;
1898   u16 *low_ports = 0;
1899   u16 *high_ports = 0;
1900   u32 vrf_id;
1901   u16 tmp_low, tmp_high;
1902   u8 num_ranges;
1903   int i;
1904
1905   // Validate port range
1906   num_ranges = mp->number_of_ranges;
1907   if (num_ranges > 32)
1908     {                           // This is size of array in VPE.API
1909       rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
1910       goto reply;
1911     }
1912
1913   vec_reset_length (low_ports);
1914   vec_reset_length (high_ports);
1915
1916   for (i = 0; i < num_ranges; i++)
1917     {
1918       tmp_low = mp->low_ports[i];
1919       tmp_high = mp->high_ports[i];
1920       // If tmp_low <= tmp_high then only need to check tmp_low = 0
1921       // If tmp_low <= tmp_high then only need to check tmp_high > 65535
1922       if (tmp_low > tmp_high || tmp_low == 0 || tmp_high > 65535)
1923         {
1924           rv = VNET_API_ERROR_INVALID_VALUE;
1925           goto reply;
1926         }
1927       vec_add1 (low_ports, tmp_low);
1928       vec_add1 (high_ports, tmp_high + 1);
1929     }
1930
1931   // Validate mask_length
1932   if ((is_ipv6 && mask_length > 128) || (!is_ipv6 && mask_length > 32))
1933     {
1934       rv = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
1935       goto reply;
1936     }
1937
1938   vrf_id = ntohl (mp->vrf_id);
1939
1940   if (vrf_id < 1)
1941     {
1942       rv = VNET_API_ERROR_INVALID_VALUE;
1943       goto reply;
1944     }
1945
1946
1947   if (is_ipv6)
1948     {
1949       clib_memcpy (ip6_addr.as_u8, mp->address, sizeof (ip6_addr.as_u8));
1950       rv = ip6_source_and_port_range_check_add_del (&ip6_addr,
1951                                                     mask_length,
1952                                                     vrf_id,
1953                                                     low_ports,
1954                                                     high_ports, is_add);
1955     }
1956   else
1957     {
1958       clib_memcpy (ip4_addr.data, mp->address, sizeof (ip4_addr));
1959       rv = ip4_source_and_port_range_check_add_del (&ip4_addr,
1960                                                     mask_length,
1961                                                     vrf_id,
1962                                                     low_ports,
1963                                                     high_ports, is_add);
1964     }
1965
1966 reply:
1967   vec_free (low_ports);
1968   vec_free (high_ports);
1969   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY);
1970 }
1971
1972 static void
1973   vl_api_ip_source_and_port_range_check_interface_add_del_t_handler
1974   (vl_api_ip_source_and_port_range_check_interface_add_del_t * mp)
1975 {
1976   vlib_main_t *vm = vlib_get_main ();
1977   vl_api_ip_source_and_port_range_check_interface_add_del_reply_t *rmp;
1978   ip4_main_t *im = &ip4_main;
1979   int rv;
1980   u32 sw_if_index;
1981   u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
1982   u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
1983   uword *p = 0;
1984   int i;
1985
1986   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] =
1987     ntohl (mp->tcp_out_vrf_id);
1988   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] =
1989     ntohl (mp->udp_out_vrf_id);
1990   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] =
1991     ntohl (mp->tcp_in_vrf_id);
1992   vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] =
1993     ntohl (mp->udp_in_vrf_id);
1994
1995
1996   for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
1997     {
1998       if (vrf_id[i] != 0 && vrf_id[i] != ~0)
1999         {
2000           p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
2001
2002           if (p == 0)
2003             {
2004               rv = VNET_API_ERROR_INVALID_VALUE;
2005               goto reply;
2006             }
2007
2008           fib_index[i] = p[0];
2009         }
2010       else
2011         fib_index[i] = ~0;
2012     }
2013   sw_if_index = ntohl (mp->sw_if_index);
2014
2015   VALIDATE_SW_IF_INDEX (mp);
2016
2017   rv =
2018     set_ip_source_and_port_range_check (vm, fib_index, sw_if_index,
2019                                         mp->is_add);
2020
2021   BAD_SW_IF_INDEX_LABEL;
2022 reply:
2023
2024   REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY);
2025 }
2026
2027 #define IP4_ARP_EVENT 3
2028 #define IP6_ND_EVENT 4
2029
2030 static int arp_change_delete_callback (u32 pool_index, u8 * notused);
2031 static int nd_change_delete_callback (u32 pool_index, u8 * notused);
2032 static vlib_node_registration_t ip_resolver_process_node;
2033
2034 static void
2035 handle_ip4_arp_event (u32 pool_index)
2036 {
2037   vpe_api_main_t *vam = &vpe_api_main;
2038   vnet_main_t *vnm = vam->vnet_main;
2039   vlib_main_t *vm = vam->vlib_main;
2040   vl_api_ip4_arp_event_t *event;
2041   vl_api_ip4_arp_event_t *mp;
2042   vl_api_registration_t *reg;
2043
2044   /* Client can cancel, die, etc. */
2045   if (pool_is_free_index (vam->arp_events, pool_index))
2046     return;
2047
2048   event = pool_elt_at_index (vam->arp_events, pool_index);
2049
2050   reg = vl_api_client_index_to_registration (event->client_index);
2051   if (!reg)
2052     {
2053       (void) vnet_add_del_ip4_arp_change_event
2054         (vnm, arp_change_delete_callback,
2055          event->pid, &event->address,
2056          ip_resolver_process_node.index, IP4_ARP_EVENT,
2057          ~0 /* pool index, notused */ , 0 /* is_add */ );
2058       return;
2059     }
2060
2061   if (vl_api_can_send_msg (reg))
2062     {
2063       mp = vl_msg_api_alloc (sizeof (*mp));
2064       clib_memcpy (mp, event, sizeof (*mp));
2065       vl_api_send_msg (reg, (u8 *) mp);
2066     }
2067   else
2068     {
2069       static f64 last_time;
2070       /*
2071        * Throttle syslog msgs.
2072        * It's pretty tempting to just revoke the registration...
2073        */
2074       if (vlib_time_now (vm) > last_time + 10.0)
2075         {
2076           clib_warning ("arp event for %U to pid %d: queue stuffed!",
2077                         format_ip4_address, &event->address, event->pid);
2078           last_time = vlib_time_now (vm);
2079         }
2080     }
2081 }
2082
2083 void
2084 handle_ip6_nd_event (u32 pool_index)
2085 {
2086   vpe_api_main_t *vam = &vpe_api_main;
2087   vnet_main_t *vnm = vam->vnet_main;
2088   vlib_main_t *vm = vam->vlib_main;
2089   vl_api_ip6_nd_event_t *event;
2090   vl_api_ip6_nd_event_t *mp;
2091   vl_api_registration_t *reg;
2092
2093   /* Client can cancel, die, etc. */
2094   if (pool_is_free_index (vam->nd_events, pool_index))
2095     return;
2096
2097   event = pool_elt_at_index (vam->nd_events, pool_index);
2098
2099   reg = vl_api_client_index_to_registration (event->client_index);
2100   if (!reg)
2101     {
2102       (void) vnet_add_del_ip6_nd_change_event
2103         (vnm, nd_change_delete_callback,
2104          event->pid, &event->address,
2105          ip_resolver_process_node.index, IP6_ND_EVENT,
2106          ~0 /* pool index, notused */ , 0 /* is_add */ );
2107       return;
2108     }
2109
2110   if (vl_api_can_send_msg (reg))
2111     {
2112       mp = vl_msg_api_alloc (sizeof (*mp));
2113       clib_memcpy (mp, event, sizeof (*mp));
2114       vl_api_send_msg (reg, (u8 *) mp);
2115     }
2116   else
2117     {
2118       static f64 last_time;
2119       /*
2120        * Throttle syslog msgs.
2121        * It's pretty tempting to just revoke the registration...
2122        */
2123       if (vlib_time_now (vm) > last_time + 10.0)
2124         {
2125           clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!",
2126                         format_ip6_address, &event->address, event->pid);
2127           last_time = vlib_time_now (vm);
2128         }
2129     }
2130 }
2131
2132 static uword
2133 resolver_process (vlib_main_t * vm,
2134                   vlib_node_runtime_t * rt, vlib_frame_t * f)
2135 {
2136   volatile f64 timeout = 100.0;
2137   volatile uword *event_data = 0;
2138
2139   while (1)
2140     {
2141       vlib_process_wait_for_event_or_clock (vm, timeout);
2142
2143       uword event_type =
2144         vlib_process_get_events (vm, (uword **) & event_data);
2145
2146       int i;
2147       switch (event_type)
2148         {
2149         case IP4_ARP_EVENT:
2150           for (i = 0; i < vec_len (event_data); i++)
2151             handle_ip4_arp_event (event_data[i]);
2152           break;
2153
2154         case IP6_ND_EVENT:
2155           for (i = 0; i < vec_len (event_data); i++)
2156             handle_ip6_nd_event (event_data[i]);
2157           break;
2158
2159         case ~0:                /* timeout */
2160           break;
2161         }
2162
2163       vec_reset_length (event_data);
2164     }
2165   return 0;                     /* or not */
2166 }
2167
2168 /* *INDENT-OFF* */
2169 VLIB_REGISTER_NODE (ip_resolver_process_node,static) = {
2170   .function = resolver_process,
2171   .type = VLIB_NODE_TYPE_PROCESS,
2172   .name = "ip-route-resolver-process",
2173 };
2174 /* *INDENT-ON* */
2175
2176 static int
2177 nd_change_data_callback (u32 pool_index, u8 * new_mac,
2178                          u32 sw_if_index, ip6_address_t * address)
2179 {
2180   vpe_api_main_t *am = &vpe_api_main;
2181   vl_api_ip6_nd_event_t *event;
2182
2183   if (pool_is_free_index (am->nd_events, pool_index))
2184     return 1;
2185
2186   event = pool_elt_at_index (am->nd_events, pool_index);
2187   if (eth_mac_equal (event->new_mac, new_mac) &&
2188       sw_if_index == ntohl (event->sw_if_index))
2189     {
2190       return 1;
2191     }
2192
2193   clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
2194   event->sw_if_index = htonl (sw_if_index);
2195   return 0;
2196 }
2197
2198 static int
2199 arp_change_delete_callback (u32 pool_index, u8 * notused)
2200 {
2201   vpe_api_main_t *am = &vpe_api_main;
2202
2203   if (pool_is_free_index (am->arp_events, pool_index))
2204     return 1;
2205
2206   pool_put_index (am->arp_events, pool_index);
2207   return 0;
2208 }
2209
2210 static int
2211 nd_change_delete_callback (u32 pool_index, u8 * notused)
2212 {
2213   vpe_api_main_t *am = &vpe_api_main;
2214
2215   if (pool_is_free_index (am->nd_events, pool_index))
2216     return 1;
2217
2218   pool_put_index (am->nd_events, pool_index);
2219   return 0;
2220 }
2221
2222 static vlib_node_registration_t wc_arp_process_node;
2223
2224 enum
2225 { WC_ARP_REPORT, WC_ND_REPORT, RA_REPORT, REPORT_MAX };
2226
2227 static uword
2228 wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
2229 {
2230   /* These cross the longjmp  boundry (vlib_process_wait_for_event)
2231    * and need to be volatile - to prevent them from being optimized into
2232    * a register - which could change during suspension */
2233
2234   volatile wc_arp_report_t arp_prev = { 0 };
2235   volatile wc_nd_report_t nd_prev = { 0 };
2236   volatile f64 last_arp = vlib_time_now (vm);
2237   volatile f64 last_nd = vlib_time_now (vm);
2238
2239   while (1)
2240     {
2241       vlib_process_wait_for_event (vm);
2242       uword event_type = WC_ARP_REPORT;
2243       void *event_data = vlib_process_get_event_data (vm, &event_type);
2244
2245       f64 now = vlib_time_now (vm);
2246       int i;
2247       if (event_type == WC_ARP_REPORT)
2248         {
2249           wc_arp_report_t *arp_events = event_data;
2250           for (i = 0; i < vec_len (arp_events); i++)
2251             {
2252               /* discard dup event */
2253               if (arp_prev.ip4 == arp_events[i].ip4 &&
2254                   eth_mac_equal ((u8 *) arp_prev.mac, arp_events[i].mac) &&
2255                   arp_prev.sw_if_index == arp_events[i].sw_if_index &&
2256                   (now - last_arp) < 10.0)
2257                 {
2258                   continue;
2259                 }
2260               arp_prev = arp_events[i];
2261               last_arp = now;
2262               vpe_client_registration_t *reg;
2263             /* *INDENT-OFF* */
2264             pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations,
2265             ({
2266               vl_api_registration_t *vl_reg;
2267               vl_reg = vl_api_client_index_to_registration (reg->client_index);
2268               ASSERT (vl_reg != NULL);
2269               if (reg && vl_api_can_send_msg (vl_reg))
2270                 {
2271                   vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event);
2272                   memset (event, 0, sizeof *event);
2273                   event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
2274                   event->client_index = reg->client_index;
2275                   event->pid = reg->client_pid;
2276                   event->mac_ip = 1;
2277                   event->address = arp_events[i].ip4;
2278                   event->sw_if_index = htonl(arp_events[i].sw_if_index);
2279                   memcpy(event->new_mac, arp_events[i].mac, sizeof event->new_mac);
2280                   vl_api_send_msg (vl_reg, (u8 *) event);
2281                 }
2282             }));
2283             /* *INDENT-ON* */
2284             }
2285         }
2286       else if (event_type == WC_ND_REPORT)
2287         {
2288           wc_nd_report_t *nd_events = event_data;
2289           for (i = 0; i < vec_len (nd_events); i++)
2290             {
2291               /* discard dup event */
2292               if (ip6_address_is_equal
2293                   ((ip6_address_t *) & nd_prev.ip6, &nd_events[i].ip6)
2294                   && eth_mac_equal ((u8 *) nd_prev.mac, nd_events[i].mac)
2295                   && nd_prev.sw_if_index == nd_events[i].sw_if_index
2296                   && (now - last_nd) < 10.0)
2297                 {
2298                   continue;
2299                 }
2300               nd_prev = nd_events[i];
2301               last_nd = now;
2302               vpe_client_registration_t *reg;
2303               /* *INDENT-OFF* */
2304               pool_foreach(reg, vpe_api_main.wc_ip6_nd_events_registrations,
2305               ({
2306                 vl_api_registration_t *vl_reg;
2307                 vl_reg = vl_api_client_index_to_registration (reg->client_index);
2308                 if (vl_reg && vl_api_can_send_msg (vl_reg))
2309                   {
2310                     vl_api_ip6_nd_event_t * event = vl_msg_api_alloc (sizeof *event);
2311                     memset (event, 0, sizeof *event);
2312                     event->_vl_msg_id = htons (VL_API_IP6_ND_EVENT);
2313                     event->client_index = reg->client_index;
2314                     event->pid = reg->client_pid;
2315                     event->mac_ip = 1;
2316                     memcpy(event->address, nd_events[i].ip6.as_u8, sizeof event->address);
2317                     event->sw_if_index = htonl(nd_events[i].sw_if_index);
2318                     memcpy(event->new_mac, nd_events[i].mac, sizeof event->new_mac);
2319                     vl_api_send_msg (vl_reg, (u8 *) event);
2320                   }
2321               }));
2322             /* *INDENT-ON* */
2323             }
2324         }
2325       else if (event_type == RA_REPORT)
2326         {
2327           ra_report_t *ra_events = event_data;
2328           for (i = 0; i < vec_len (ra_events); i++)
2329             {
2330               ip6_neighbor_public_main_t *npm = &ip6_neighbor_public_main;
2331               call_ip6_neighbor_callbacks (&ra_events[i],
2332                                            npm->ra_report_functions);
2333
2334               vpe_client_registration_t *reg;
2335               /* *INDENT-OFF* */
2336               pool_foreach(reg, vpe_api_main.ip6_ra_events_registrations,
2337               ({
2338                 vl_api_registration_t *vl_reg;
2339                 vl_reg =
2340                   vl_api_client_index_to_registration (reg->client_index);
2341                 if (vl_reg && vl_api_can_send_msg (vl_reg))
2342                   {
2343                     u32 event_size =
2344                       sizeof (vl_api_ip6_ra_event_t) +
2345                       vec_len (ra_events[i].prefixes) *
2346                       sizeof (vl_api_ip6_ra_prefix_info_t);
2347                     vl_api_ip6_ra_event_t *event =
2348                       vl_msg_api_alloc (event_size);
2349                     memset (event, 0, event_size);
2350                     event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT);
2351                     event->client_index = reg->client_index;
2352                     event->pid = reg->client_pid;
2353
2354                     event->sw_if_index = clib_host_to_net_u32 (ra_events[i].sw_if_index);
2355
2356                     memcpy (event->router_address, ra_events[i].router_address, 16);
2357
2358                     event->current_hop_limit = ra_events[i].current_hop_limit;
2359                     event->flags = ra_events[i].flags;
2360                     event->router_lifetime_in_sec =
2361                       clib_host_to_net_u16 (ra_events
2362                                             [i].router_lifetime_in_sec);
2363                     event->neighbor_reachable_time_in_msec =
2364                       clib_host_to_net_u32 (ra_events
2365                                             [i].neighbor_reachable_time_in_msec);
2366                     event->time_in_msec_between_retransmitted_neighbor_solicitations
2367                       =
2368                       clib_host_to_net_u32 (ra_events
2369                                             [i].time_in_msec_between_retransmitted_neighbor_solicitations);
2370
2371                     event->n_prefixes =
2372                       clib_host_to_net_u32 (vec_len (ra_events[i].prefixes));
2373                     vl_api_ip6_ra_prefix_info_t *prefix =
2374                       (typeof (prefix)) event->prefixes;
2375                     u32 j;
2376                     for (j = 0; j < vec_len (ra_events[i].prefixes); j++)
2377                       {
2378                         ra_report_prefix_info_t *info =
2379                           &ra_events[i].prefixes[j];
2380                         memcpy (prefix->dst_address, info->dst_address.as_u8,
2381                                 16);
2382                         prefix->dst_address_length = info->dst_address_length;
2383                         prefix->flags = info->flags;
2384                         prefix->valid_time =
2385                           clib_host_to_net_u32 (info->valid_time);
2386                         prefix->preferred_time =
2387                           clib_host_to_net_u32 (info->preferred_time);
2388                         prefix++;
2389                       }
2390
2391                     vl_api_send_msg (vl_reg, (u8 *) event);
2392                   }
2393               }));
2394             /* *INDENT-ON* */
2395             }
2396         }
2397       vlib_process_put_event_data (vm, event_data);
2398     }
2399
2400   return 0;
2401 }
2402
2403 /* *INDENT-OFF* */
2404 VLIB_REGISTER_NODE (wc_arp_process_node,static) = {
2405   .function = wc_arp_process,
2406   .type = VLIB_NODE_TYPE_PROCESS,
2407   .name = "wildcard-ip4-arp-publisher-process",
2408 };
2409 /* *INDENT-ON* */
2410
2411 static int
2412 arp_change_data_callback (u32 pool_index, u8 * new_mac,
2413                           u32 sw_if_index, u32 address)
2414 {
2415   vpe_api_main_t *am = &vpe_api_main;
2416   vl_api_ip4_arp_event_t *event;
2417
2418   if (pool_is_free_index (am->arp_events, pool_index))
2419     return 1;
2420
2421   event = pool_elt_at_index (am->arp_events, pool_index);
2422   if (eth_mac_equal (event->new_mac, new_mac) &&
2423       sw_if_index == ntohl (event->sw_if_index))
2424     {
2425       return 1;
2426     }
2427
2428   clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
2429   event->sw_if_index = htonl (sw_if_index);
2430   return 0;
2431 }
2432
2433 static void
2434 vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
2435 {
2436   vpe_api_main_t *am = &vpe_api_main;
2437   vnet_main_t *vnm = vnet_get_main ();
2438   vl_api_want_ip4_arp_events_reply_t *rmp;
2439   int rv = 0;
2440
2441   if (mp->address == 0)
2442     {
2443       uword *p =
2444         hash_get (am->wc_ip4_arp_events_registration_hash, mp->client_index);
2445       vpe_client_registration_t *rp;
2446       if (p)
2447         {
2448           if (mp->enable_disable)
2449             {
2450               clib_warning ("pid %d: already enabled...", mp->pid);
2451               rv = VNET_API_ERROR_INVALID_REGISTRATION;
2452               goto reply;
2453             }
2454           else
2455             {
2456               rp =
2457                 pool_elt_at_index (am->wc_ip4_arp_events_registrations, p[0]);
2458               pool_put (am->wc_ip4_arp_events_registrations, rp);
2459               hash_unset (am->wc_ip4_arp_events_registration_hash,
2460                           mp->client_index);
2461               if (pool_elts (am->wc_ip4_arp_events_registrations) == 0)
2462                 wc_arp_set_publisher_node (~0, REPORT_MAX);
2463               goto reply;
2464             }
2465         }
2466       if (mp->enable_disable == 0)
2467         {
2468           clib_warning ("pid %d: already disabled...", mp->pid);
2469           rv = VNET_API_ERROR_INVALID_REGISTRATION;
2470           goto reply;
2471         }
2472       pool_get (am->wc_ip4_arp_events_registrations, rp);
2473       rp->client_index = mp->client_index;
2474       rp->client_pid = mp->pid;
2475       hash_set (am->wc_ip4_arp_events_registration_hash, rp->client_index,
2476                 rp - am->wc_ip4_arp_events_registrations);
2477       wc_arp_set_publisher_node (wc_arp_process_node.index, WC_ARP_REPORT);
2478       goto reply;
2479     }
2480
2481   if (mp->enable_disable)
2482     {
2483       vl_api_ip4_arp_event_t *event;
2484       pool_get (am->arp_events, event);
2485       rv = vnet_add_del_ip4_arp_change_event
2486         (vnm, arp_change_data_callback,
2487          mp->pid, &mp->address /* addr, in net byte order */ ,
2488          ip_resolver_process_node.index,
2489          IP4_ARP_EVENT, event - am->arp_events, 1 /* is_add */ );
2490
2491       if (rv)
2492         {
2493           pool_put (am->arp_events, event);
2494           goto reply;
2495         }
2496       memset (event, 0, sizeof (*event));
2497
2498       /* Python API expects events to have no context */
2499       event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
2500       event->client_index = mp->client_index;
2501       event->address = mp->address;
2502       event->pid = mp->pid;
2503       if (mp->address == 0)
2504         event->mac_ip = 1;
2505     }
2506   else
2507     {
2508       rv = vnet_add_del_ip4_arp_change_event
2509         (vnm, arp_change_delete_callback,
2510          mp->pid, &mp->address /* addr, in net byte order */ ,
2511          ip_resolver_process_node.index,
2512          IP4_ARP_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
2513     }
2514 reply:
2515   REPLY_MACRO (VL_API_WANT_IP4_ARP_EVENTS_REPLY);
2516 }
2517
2518 static void
2519 vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
2520 {
2521   vpe_api_main_t *am = &vpe_api_main;
2522   vnet_main_t *vnm = vnet_get_main ();
2523   vl_api_want_ip6_nd_events_reply_t *rmp;
2524   int rv = 0;
2525
2526   if (ip6_address_is_zero ((ip6_address_t *) mp->address))
2527     {
2528       uword *p =
2529         hash_get (am->wc_ip6_nd_events_registration_hash, mp->client_index);
2530       vpe_client_registration_t *rp;
2531       if (p)
2532         {
2533           if (mp->enable_disable)
2534             {
2535               clib_warning ("pid %d: already enabled...", mp->pid);
2536               rv = VNET_API_ERROR_INVALID_REGISTRATION;
2537               goto reply;
2538             }
2539           else
2540             {
2541               rp =
2542                 pool_elt_at_index (am->wc_ip6_nd_events_registrations, p[0]);
2543               pool_put (am->wc_ip6_nd_events_registrations, rp);
2544               hash_unset (am->wc_ip6_nd_events_registration_hash,
2545                           mp->client_index);
2546               if (pool_elts (am->wc_ip6_nd_events_registrations) == 0)
2547                 wc_nd_set_publisher_node (~0, REPORT_MAX);
2548               goto reply;
2549             }
2550         }
2551       if (mp->enable_disable == 0)
2552         {
2553           clib_warning ("pid %d: already disabled...", mp->pid);
2554           rv = VNET_API_ERROR_INVALID_REGISTRATION;
2555           goto reply;
2556         }
2557       pool_get (am->wc_ip6_nd_events_registrations, rp);
2558       rp->client_index = mp->client_index;
2559       rp->client_pid = mp->pid;
2560       hash_set (am->wc_ip6_nd_events_registration_hash, rp->client_index,
2561                 rp - am->wc_ip6_nd_events_registrations);
2562       wc_nd_set_publisher_node (wc_arp_process_node.index, WC_ND_REPORT);
2563       goto reply;
2564     }
2565
2566   if (mp->enable_disable)
2567     {
2568       vl_api_ip6_nd_event_t *event;
2569       pool_get (am->nd_events, event);
2570
2571       rv = vnet_add_del_ip6_nd_change_event
2572         (vnm, nd_change_data_callback,
2573          mp->pid, mp->address /* addr, in net byte order */ ,
2574          ip_resolver_process_node.index,
2575          IP6_ND_EVENT, event - am->nd_events, 1 /* is_add */ );
2576
2577       if (rv)
2578         {
2579           pool_put (am->nd_events, event);
2580           goto reply;
2581         }
2582       memset (event, 0, sizeof (*event));
2583
2584       event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT);
2585       event->client_index = mp->client_index;
2586       clib_memcpy (event->address, mp->address, sizeof event->address);
2587       event->pid = mp->pid;
2588     }
2589   else
2590     {
2591       rv = vnet_add_del_ip6_nd_change_event
2592         (vnm, nd_change_delete_callback,
2593          mp->pid, mp->address /* addr, in net byte order */ ,
2594          ip_resolver_process_node.index,
2595          IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
2596     }
2597 reply:
2598   REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY);
2599 }
2600
2601 static void
2602 vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
2603 {
2604   vpe_api_main_t *am = &vpe_api_main;
2605   vl_api_want_ip6_ra_events_reply_t *rmp;
2606   int rv = 0;
2607
2608   uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
2609   vpe_client_registration_t *rp;
2610   if (p)
2611     {
2612       if (mp->enable_disable)
2613         {
2614           clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
2615           rv = VNET_API_ERROR_INVALID_REGISTRATION;
2616           goto reply;
2617         }
2618       else
2619         {
2620           rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
2621           pool_put (am->ip6_ra_events_registrations, rp);
2622           hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
2623           goto reply;
2624         }
2625     }
2626   if (mp->enable_disable == 0)
2627     {
2628       clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
2629       rv = VNET_API_ERROR_INVALID_REGISTRATION;
2630       goto reply;
2631     }
2632   pool_get (am->ip6_ra_events_registrations, rp);
2633   rp->client_index = mp->client_index;
2634   rp->client_pid = ntohl (mp->pid);
2635   hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
2636             rp - am->ip6_ra_events_registrations);
2637
2638 reply:
2639   REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
2640 }
2641
2642 static void
2643 vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp)
2644 {
2645   vl_api_proxy_arp_add_del_reply_t *rmp;
2646   u32 fib_index;
2647   int rv;
2648   ip4_main_t *im = &ip4_main;
2649   int vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
2650                               ip4_address_t * hi_addr,
2651                               u32 fib_index, int is_del);
2652   uword *p;
2653
2654   stats_dslock_with_hint (1 /* release hint */ , 6 /* tag */ );
2655
2656   p = hash_get (im->fib_index_by_table_id, ntohl (mp->vrf_id));
2657
2658   if (!p)
2659     {
2660       rv = VNET_API_ERROR_NO_SUCH_FIB;
2661       goto out;
2662     }
2663
2664   fib_index = p[0];
2665
2666   rv = vnet_proxy_arp_add_del ((ip4_address_t *) mp->low_address,
2667                                (ip4_address_t *) mp->hi_address,
2668                                fib_index, mp->is_add == 0);
2669
2670 out:
2671   stats_dsunlock ();
2672   REPLY_MACRO (VL_API_PROXY_ARP_ADD_DEL_REPLY);
2673 }
2674
2675 static void
2676   vl_api_proxy_arp_intfc_enable_disable_t_handler
2677   (vl_api_proxy_arp_intfc_enable_disable_t * mp)
2678 {
2679   int rv = 0;
2680   vnet_main_t *vnm = vnet_get_main ();
2681   vl_api_proxy_arp_intfc_enable_disable_reply_t *rmp;
2682
2683   VALIDATE_SW_IF_INDEX (mp);
2684
2685   vnet_sw_interface_t *si =
2686     vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
2687
2688   ASSERT (si);
2689
2690   if (mp->enable_disable)
2691     si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2692   else
2693     si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2694
2695   BAD_SW_IF_INDEX_LABEL;
2696
2697   REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
2698 }
2699
2700 static void
2701 vl_api_ip_probe_neighbor_t_handler (vl_api_ip_probe_neighbor_t * mp)
2702 {
2703   int rv = 0;
2704   vlib_main_t *vm = vlib_get_main ();
2705   vl_api_ip_probe_neighbor_reply_t *rmp;
2706   clib_error_t *error;
2707
2708   VALIDATE_SW_IF_INDEX (mp);
2709
2710   u32 sw_if_index = ntohl (mp->sw_if_index);
2711
2712   if (mp->is_ipv6)
2713     error = ip6_probe_neighbor (vm, (ip6_address_t *) mp->dst_address,
2714                                 sw_if_index);
2715   else
2716     error = ip4_probe_neighbor (vm, (ip4_address_t *) mp->dst_address,
2717                                 sw_if_index);
2718
2719   if (error)
2720     {
2721       clib_error_report (error);
2722       rv = clib_error_get_code (error);
2723     }
2724
2725   BAD_SW_IF_INDEX_LABEL;
2726
2727   REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
2728 }
2729
2730 static void
2731   vl_api_ip_scan_neighbor_enable_disable_t_handler
2732   (vl_api_ip_scan_neighbor_enable_disable_t * mp)
2733 {
2734   int rv = 0;
2735   vl_api_ip_scan_neighbor_enable_disable_reply_t *rmp;
2736   ip_neighbor_scan_arg_t arg;
2737
2738   arg.mode = mp->mode;
2739   arg.scan_interval = mp->scan_interval;
2740   arg.max_proc_time = mp->max_proc_time;
2741   arg.max_update = mp->max_update;
2742   arg.scan_int_delay = mp->scan_int_delay;
2743   arg.stale_threshold = mp->stale_threshold;
2744   ip_neighbor_scan_enable_disable (&arg);
2745
2746   REPLY_MACRO (VL_API_IP_SCAN_NEIGHBOR_ENABLE_DISABLE_REPLY);
2747 }
2748
2749 static int
2750 ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
2751 {
2752   vnet_main_t *vnm = vnet_get_main ();
2753   vnet_interface_main_t *im = &vnm->interface_main;
2754   ip4_main_t *im4 = &ip4_main;
2755   static u32 *sw_if_indices_to_shut;
2756   fib_table_t *fib_table;
2757   ip4_fib_t *fib;
2758   u32 sw_if_index;
2759   int i;
2760   int rv = VNET_API_ERROR_NO_SUCH_FIB;
2761   u32 target_fib_id = ntohl (mp->vrf_id);
2762
2763   stats_dslock_with_hint (1 /* release hint */ , 8 /* tag */ );
2764
2765   /* *INDENT-OFF* */
2766   pool_foreach (fib_table, im4->fibs,
2767   ({
2768     vnet_sw_interface_t * si;
2769
2770     fib = pool_elt_at_index (im4->v4_fibs, fib_table->ft_index);
2771
2772     if (fib->table_id != target_fib_id)
2773       continue;
2774
2775     /* remove any mpls encap/decap labels */
2776     mpls_fib_reset_labels (fib->table_id);
2777
2778     /* remove any proxy arps in this fib */
2779     vnet_proxy_arp_fib_reset (fib->table_id);
2780
2781     /* Set the flow hash for this fib to the default */
2782     vnet_set_ip4_flow_hash (fib->table_id, IP_FLOW_HASH_DEFAULT);
2783
2784     vec_reset_length (sw_if_indices_to_shut);
2785
2786     /* Shut down interfaces in this FIB / clean out intfc routes */
2787     pool_foreach (si, im->sw_interfaces,
2788     ({
2789       u32 sw_if_index = si->sw_if_index;
2790
2791       if (sw_if_index < vec_len (im4->fib_index_by_sw_if_index)
2792           && (im4->fib_index_by_sw_if_index[si->sw_if_index] ==
2793               fib->index))
2794         vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
2795     }));
2796
2797     for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
2798       sw_if_index = sw_if_indices_to_shut[i];
2799
2800       u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
2801       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
2802       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
2803     }
2804
2805     fib_table_flush(fib->index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
2806
2807     rv = 0;
2808     break;
2809     })); /* pool_foreach (fib) */
2810     /* *INDENT-ON* */
2811
2812   stats_dsunlock ();
2813   return rv;
2814 }
2815
2816 static int
2817 ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
2818 {
2819   vnet_main_t *vnm = vnet_get_main ();
2820   vnet_interface_main_t *im = &vnm->interface_main;
2821   ip6_main_t *im6 = &ip6_main;
2822   static u32 *sw_if_indices_to_shut;
2823   fib_table_t *fib_table;
2824   ip6_fib_t *fib;
2825   u32 sw_if_index;
2826   int i;
2827   int rv = VNET_API_ERROR_NO_SUCH_FIB;
2828   u32 target_fib_id = ntohl (mp->vrf_id);
2829
2830   stats_dslock_with_hint (1 /* release hint */ , 9 /* tag */ );
2831
2832   /* *INDENT-OFF* */
2833   pool_foreach (fib_table, im6->fibs,
2834   ({
2835     vnet_sw_interface_t * si;
2836
2837     fib = pool_elt_at_index (im6->v6_fibs, fib_table->ft_index);
2838
2839     if (fib->table_id != target_fib_id)
2840       continue;
2841
2842     vec_reset_length (sw_if_indices_to_shut);
2843
2844     /* Set the flow hash for this fib to the default */
2845     vnet_set_ip6_flow_hash (fib->table_id, IP_FLOW_HASH_DEFAULT);
2846
2847     /* Shut down interfaces in this FIB / clean out intfc routes */
2848     pool_foreach (si, im->sw_interfaces,
2849     ({
2850       if (im6->fib_index_by_sw_if_index[si->sw_if_index] ==
2851           fib->index)
2852         vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
2853     }));
2854
2855     for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
2856       sw_if_index = sw_if_indices_to_shut[i];
2857
2858       u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
2859       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
2860       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
2861     }
2862
2863     fib_table_flush(fib->index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
2864
2865     rv = 0;
2866     break;
2867   })); /* pool_foreach (fib) */
2868   /* *INDENT-ON* */
2869
2870   stats_dsunlock ();
2871   return rv;
2872 }
2873
2874 static void
2875 vl_api_reset_fib_t_handler (vl_api_reset_fib_t * mp)
2876 {
2877   int rv;
2878   vl_api_reset_fib_reply_t *rmp;
2879
2880   if (mp->is_ipv6)
2881     rv = ip6_reset_fib_t_handler (mp);
2882   else
2883     rv = ip4_reset_fib_t_handler (mp);
2884
2885   REPLY_MACRO (VL_API_RESET_FIB_REPLY);
2886 }
2887
2888 static void
2889 vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp)
2890 {
2891   int rv;
2892   vl_api_set_arp_neighbor_limit_reply_t *rmp;
2893   vnet_main_t *vnm = vnet_get_main ();
2894   clib_error_t *error;
2895
2896   vnm->api_errno = 0;
2897
2898   if (mp->is_ipv6)
2899     error = ip6_set_neighbor_limit (ntohl (mp->arp_neighbor_limit));
2900   else
2901     error = ip4_set_arp_limit (ntohl (mp->arp_neighbor_limit));
2902
2903   if (error)
2904     {
2905       clib_error_report (error);
2906       rv = VNET_API_ERROR_UNSPECIFIED;
2907     }
2908   else
2909     {
2910       rv = vnm->api_errno;
2911     }
2912
2913   REPLY_MACRO (VL_API_SET_ARP_NEIGHBOR_LIMIT_REPLY);
2914 }
2915
2916 void
2917 vl_api_ip_reassembly_set_t_handler (vl_api_ip_reassembly_set_t * mp)
2918 {
2919   vl_api_ip_reassembly_set_reply_t *rmp;
2920   int rv = 0;
2921   if (mp->is_ip6)
2922     {
2923       rv = ip6_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
2924                           clib_net_to_host_u32 (mp->max_reassemblies),
2925                           clib_net_to_host_u32 (mp->expire_walk_interval_ms));
2926     }
2927   else
2928     {
2929       rv = ip4_reass_set (clib_net_to_host_u32 (mp->timeout_ms),
2930                           clib_net_to_host_u32 (mp->max_reassemblies),
2931                           clib_net_to_host_u32 (mp->expire_walk_interval_ms));
2932     }
2933
2934   REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
2935 }
2936
2937 void
2938 vl_api_ip_reassembly_get_t_handler (vl_api_ip_reassembly_get_t * mp)
2939 {
2940   unix_shared_memory_queue_t *q;
2941
2942   q = vl_api_client_index_to_input_queue (mp->client_index);
2943
2944   if (q == 0)
2945     return;
2946
2947   vl_api_ip_reassembly_get_reply_t *rmp = vl_msg_api_alloc (sizeof (*rmp));
2948   memset (rmp, 0, sizeof (*rmp));
2949   rmp->_vl_msg_id = ntohs (VL_API_IP_REASSEMBLY_GET_REPLY);
2950   rmp->context = mp->context;
2951   rmp->retval = 0;
2952   if (mp->is_ip6)
2953     {
2954       rmp->is_ip6 = 1;
2955       ip6_reass_get (&rmp->timeout_ms, &rmp->max_reassemblies,
2956                      &rmp->expire_walk_interval_ms);
2957     }
2958   else
2959     {
2960       rmp->is_ip6 = 0;
2961       ip4_reass_get (&rmp->timeout_ms, &rmp->max_reassemblies,
2962                      &rmp->expire_walk_interval_ms);
2963     }
2964   rmp->timeout_ms = clib_host_to_net_u32 (rmp->timeout_ms);
2965   rmp->max_reassemblies = clib_host_to_net_u32 (rmp->max_reassemblies);
2966   rmp->expire_walk_interval_ms =
2967     clib_host_to_net_u32 (rmp->expire_walk_interval_ms);
2968   vl_msg_api_send_shmem (q, (u8 *) & rmp);
2969 }
2970
2971 void
2972   vl_api_ip_reassembly_enable_disable_t_handler
2973   (vl_api_ip_reassembly_enable_disable_t * mp)
2974 {
2975   vl_api_ip_reassembly_enable_disable_reply_t *rmp;
2976   int rv = 0;
2977   rv = ip4_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
2978                                  mp->enable_ip4);
2979   if (0 == rv)
2980     {
2981       rv = ip6_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
2982                                      mp->enable_ip6);
2983     }
2984
2985   REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
2986 }
2987
2988 #define vl_msg_name_crc_list
2989 #include <vnet/ip/ip.api.h>
2990 #undef vl_msg_name_crc_list
2991
2992 static void
2993 setup_message_id_table (api_main_t * am)
2994 {
2995 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
2996   foreach_vl_msg_name_crc_ip;
2997 #undef _
2998 }
2999
3000 static clib_error_t *
3001 ip_api_hookup (vlib_main_t * vm)
3002 {
3003   api_main_t *am = &api_main;
3004
3005 #define _(N,n)                                                  \
3006     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
3007                            vl_api_##n##_t_handler,              \
3008                            vl_noop_handler,                     \
3009                            vl_api_##n##_t_endian,               \
3010                            vl_api_##n##_t_print,                \
3011                            sizeof(vl_api_##n##_t), 1);
3012   foreach_ip_api_msg;
3013 #undef _
3014
3015   /*
3016    * Set up the (msg_name, crc, message-id) table
3017    */
3018   setup_message_id_table (am);
3019
3020   ra_set_publisher_node (wc_arp_process_node.index, RA_REPORT);
3021
3022   return 0;
3023 }
3024
3025 VLIB_API_INIT_FUNCTION (ip_api_hookup);
3026
3027 /*
3028  * fd.io coding-style-patch-verification: ON
3029  *
3030  * Local Variables:
3031  * eval: (c-set-style "gnu")
3032  * End:
3033  */