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