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