Add a name to the creation of an IP and MPLS table
[vpp.git] / src / vnet / ip / ip_api.c
1 /*
2  *------------------------------------------------------------------
3  * ip_api.c - vnet ip api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25 #include <vnet/ethernet/ethernet.h>
26 #include <vnet/ip/ip.h>
27 #include <vnet/ip/ip6_neighbor.h>
28 #include <vnet/fib/fib_table.h>
29 #include <vnet/fib/fib_api.h>
30 #include <vnet/dpo/drop_dpo.h>
31 #include <vnet/dpo/receive_dpo.h>
32 #include <vnet/dpo/lookup_dpo.h>
33 #include <vnet/dpo/classify_dpo.h>
34 #include <vnet/dpo/ip_null_dpo.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
41 #include <vnet/vnet_msg_enum.h>
42
43 #define vl_typedefs             /* define message structures */
44 #include <vnet/vnet_all_api_h.h>
45 #undef vl_typedefs
46
47 #define vl_endianfun            /* define message structures */
48 #include <vnet/vnet_all_api_h.h>
49 #undef vl_endianfun
50
51 /* instantiate all the print functions we know about */
52 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
53 #define vl_printfun
54 #include <vnet/vnet_all_api_h.h>
55 #undef vl_printfun
56
57 #include <vlibapi/api_helper_macros.h>
58
59
60 #define foreach_ip_api_msg                                              \
61 _(IP_FIB_DUMP, ip_fib_dump)                                             \
62 _(IP6_FIB_DUMP, ip6_fib_dump)                                           \
63 _(IP_MFIB_DUMP, ip_mfib_dump)                                           \
64 _(IP6_MFIB_DUMP, ip6_mfib_dump)                                         \
65 _(IP_NEIGHBOR_DUMP, ip_neighbor_dump)                                   \
66 _(IP_MROUTE_ADD_DEL, ip_mroute_add_del)                                 \
67 _(MFIB_SIGNAL_DUMP, mfib_signal_dump)                                   \
68 _(IP_ADDRESS_DUMP, ip_address_dump)                                     \
69 _(IP_DUMP, ip_dump)                                                     \
70 _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del)                             \
71 _(IP_ADD_DEL_ROUTE, ip_add_del_route)                                   \
72 _(IP_TABLE_ADD_DEL, ip_table_add_del)                                   \
73 _(SET_IP_FLOW_HASH,set_ip_flow_hash)                                    \
74 _(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config)           \
75 _(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix)           \
76 _(IP6ND_PROXY_ADD_DEL, ip6nd_proxy_add_del)                             \
77 _(IP6ND_PROXY_DUMP, ip6nd_proxy_dump)                                   \
78 _(SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable )    \
79 _(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS,                              \
80   sw_interface_ip6_set_link_local_address)
81
82 extern void stats_dslock_with_hint (int hint, int tag);
83 extern void stats_dsunlock (void);
84
85 static void
86 send_ip_neighbor_details (u8 is_ipv6,
87                           u8 is_static,
88                           u8 * mac_address,
89                           u8 * ip_address,
90                           unix_shared_memory_queue_t * q, u32 context)
91 {
92   vl_api_ip_neighbor_details_t *mp;
93
94   mp = vl_msg_api_alloc (sizeof (*mp));
95   memset (mp, 0, sizeof (*mp));
96   mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS);
97   mp->context = context;
98   mp->is_ipv6 = is_ipv6;
99   mp->is_static = is_static;
100   memcpy (mp->mac_address, mac_address, 6);
101   memcpy (mp->ip_address, ip_address, (is_ipv6) ? 16 : 4);
102
103   vl_msg_api_send_shmem (q, (u8 *) & mp);
104 }
105
106 static void
107 vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
108 {
109   unix_shared_memory_queue_t *q;
110
111   q = vl_api_client_index_to_input_queue (mp->client_index);
112   if (q == 0)
113     return;
114
115   u32 sw_if_index = ntohl (mp->sw_if_index);
116
117   if (mp->is_ipv6)
118     {
119       ip6_neighbor_t *n, *ns;
120
121       ns = ip6_neighbors_entries (sw_if_index);
122       /* *INDENT-OFF* */
123       vec_foreach (n, ns)
124       {
125         send_ip_neighbor_details
126           (mp->is_ipv6, ((n->flags & IP6_NEIGHBOR_FLAG_STATIC) ? 1 : 0),
127            (u8 *) n->link_layer_address,
128            (u8 *) & (n->key.ip6_address.as_u8),
129            q, mp->context);
130       }
131       /* *INDENT-ON* */
132       vec_free (ns);
133     }
134   else
135     {
136       ethernet_arp_ip4_entry_t *n, *ns;
137
138       ns = ip4_neighbor_entries (sw_if_index);
139       /* *INDENT-OFF* */
140       vec_foreach (n, ns)
141       {
142         send_ip_neighbor_details (mp->is_ipv6,
143           ((n->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? 1 : 0),
144           (u8*) n->ethernet_address,
145           (u8*) & (n->ip4_address.as_u8),
146           q, mp->context);
147       }
148       /* *INDENT-ON* */
149       vec_free (ns);
150     }
151 }
152
153
154 void
155 copy_fib_next_hop (fib_route_path_encode_t * api_rpath, void *fp_arg)
156 {
157   int is_ip4;
158   vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg;
159
160   if (api_rpath->rpath.frp_proto == DPO_PROTO_IP4)
161     fp->afi = IP46_TYPE_IP4;
162   else if (api_rpath->rpath.frp_proto == DPO_PROTO_IP6)
163     fp->afi = IP46_TYPE_IP6;
164   else
165     {
166       is_ip4 = ip46_address_is_ip4 (&api_rpath->rpath.frp_addr);
167       if (is_ip4)
168         fp->afi = IP46_TYPE_IP4;
169       else
170         fp->afi = IP46_TYPE_IP6;
171     }
172   if (fp->afi == IP46_TYPE_IP4)
173     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip4,
174             sizeof (api_rpath->rpath.frp_addr.ip4));
175   else
176     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip6,
177             sizeof (api_rpath->rpath.frp_addr.ip6));
178 }
179
180 static void
181 send_ip_fib_details (vpe_api_main_t * am,
182                      unix_shared_memory_queue_t * q,
183                      const fib_table_t * table,
184                      const fib_prefix_t * pfx,
185                      fib_route_path_encode_t * api_rpaths, u32 context)
186 {
187   vl_api_ip_fib_details_t *mp;
188   fib_route_path_encode_t *api_rpath;
189   vl_api_fib_path_t *fp;
190   int path_count;
191
192   path_count = vec_len (api_rpaths);
193   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
194   if (!mp)
195     return;
196   memset (mp, 0, sizeof (*mp));
197   mp->_vl_msg_id = ntohs (VL_API_IP_FIB_DETAILS);
198   mp->context = context;
199
200   mp->table_id = htonl (table->ft_table_id);
201   memcpy (mp->table_name, table->ft_desc,
202           clib_min (vec_len (table->ft_desc), sizeof (mp->table_name)));
203   mp->address_length = pfx->fp_len;
204   memcpy (mp->address, &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
205
206   mp->count = htonl (path_count);
207   fp = mp->path;
208   vec_foreach (api_rpath, api_rpaths)
209   {
210     memset (fp, 0, sizeof (*fp));
211     switch (api_rpath->dpo.dpoi_type)
212       {
213       case DPO_RECEIVE:
214         fp->is_local = true;
215         break;
216       case DPO_DROP:
217         fp->is_drop = true;
218         break;
219       case DPO_IP_NULL:
220         switch (api_rpath->dpo.dpoi_index)
221           {
222           case IP_NULL_ACTION_NONE:
223             fp->is_drop = true;
224             break;
225           case IP_NULL_ACTION_SEND_ICMP_UNREACH:
226             fp->is_unreach = true;
227             break;
228           case IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
229             fp->is_prohibit = true;
230             break;
231           default:
232             break;
233           }
234         break;
235       default:
236         break;
237       }
238     fp->weight = api_rpath->rpath.frp_weight;
239     fp->preference = api_rpath->rpath.frp_preference;
240     fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
241     copy_fib_next_hop (api_rpath, fp);
242     fp++;
243   }
244
245   vl_msg_api_send_shmem (q, (u8 *) & mp);
246 }
247
248 typedef struct vl_api_ip_fib_dump_walk_ctx_t_
249 {
250   fib_node_index_t *feis;
251 } vl_api_ip_fib_dump_walk_ctx_t;
252
253 static int
254 vl_api_ip_fib_dump_walk (fib_node_index_t fei, void *arg)
255 {
256   vl_api_ip_fib_dump_walk_ctx_t *ctx = arg;
257
258   vec_add1 (ctx->feis, fei);
259
260   return (1);
261 }
262
263 static void
264 vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
265 {
266   vpe_api_main_t *am = &vpe_api_main;
267   unix_shared_memory_queue_t *q;
268   ip4_main_t *im = &ip4_main;
269   fib_table_t *fib_table;
270   fib_node_index_t *lfeip;
271   fib_prefix_t pfx;
272   u32 fib_index;
273   fib_route_path_encode_t *api_rpaths;
274   vl_api_ip_fib_dump_walk_ctx_t ctx = {
275     .feis = NULL,
276   };
277
278   q = vl_api_client_index_to_input_queue (mp->client_index);
279   if (q == 0)
280     return;
281
282   /* *INDENT-OFF* */
283   pool_foreach (fib_table, im->fibs,
284   ({
285     fib_table_walk(fib_table->ft_index,
286                    FIB_PROTOCOL_IP4,
287                    vl_api_ip_fib_dump_walk,
288                    &ctx);
289   }));
290   /* *INDENT-ON* */
291
292   vec_sort_with_function (ctx.feis, fib_entry_cmp_for_sort);
293
294   vec_foreach (lfeip, ctx.feis)
295   {
296     fib_entry_get_prefix (*lfeip, &pfx);
297     fib_index = fib_entry_get_fib_index (*lfeip);
298     fib_table = fib_table_get (fib_index, pfx.fp_proto);
299     api_rpaths = NULL;
300     fib_entry_encode (*lfeip, &api_rpaths);
301     send_ip_fib_details (am, q, fib_table, &pfx, api_rpaths, mp->context);
302     vec_free (api_rpaths);
303   }
304
305   vec_free (ctx.feis);
306 }
307
308 static void
309 send_ip6_fib_details (vpe_api_main_t * am,
310                       unix_shared_memory_queue_t * q,
311                       u32 table_id, fib_prefix_t * pfx,
312                       fib_route_path_encode_t * api_rpaths, u32 context)
313 {
314   vl_api_ip6_fib_details_t *mp;
315   fib_route_path_encode_t *api_rpath;
316   vl_api_fib_path_t *fp;
317   int path_count;
318
319   path_count = vec_len (api_rpaths);
320   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
321   if (!mp)
322     return;
323   memset (mp, 0, sizeof (*mp));
324   mp->_vl_msg_id = ntohs (VL_API_IP6_FIB_DETAILS);
325   mp->context = context;
326
327   mp->table_id = htonl (table_id);
328   mp->address_length = pfx->fp_len;
329   memcpy (mp->address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
330
331   mp->count = htonl (path_count);
332   fp = mp->path;
333   vec_foreach (api_rpath, api_rpaths)
334   {
335     memset (fp, 0, sizeof (*fp));
336     switch (api_rpath->dpo.dpoi_type)
337       {
338       case DPO_RECEIVE:
339         fp->is_local = true;
340         break;
341       case DPO_DROP:
342         fp->is_drop = true;
343         break;
344       case DPO_IP_NULL:
345         switch (api_rpath->dpo.dpoi_index)
346           {
347           case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_NONE:
348             fp->is_drop = true;
349             break;
350           case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_SEND_ICMP_UNREACH:
351             fp->is_unreach = true;
352             break;
353           case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
354             fp->is_prohibit = true;
355             break;
356           default:
357             break;
358           }
359         break;
360       default:
361         break;
362       }
363     fp->weight = api_rpath->rpath.frp_weight;
364     fp->preference = api_rpath->rpath.frp_preference;
365     fp->sw_if_index = api_rpath->rpath.frp_sw_if_index;
366     copy_fib_next_hop (api_rpath, fp);
367     fp++;
368   }
369
370   vl_msg_api_send_shmem (q, (u8 *) & mp);
371 }
372
373 typedef struct apt_ip6_fib_show_ctx_t_
374 {
375   u32 fib_index;
376   fib_node_index_t *entries;
377 } api_ip6_fib_show_ctx_t;
378
379 static void
380 api_ip6_fib_table_put_entries (clib_bihash_kv_24_8_t * kvp, void *arg)
381 {
382   api_ip6_fib_show_ctx_t *ctx = arg;
383
384   if ((kvp->key[2] >> 32) == ctx->fib_index)
385     {
386       vec_add1 (ctx->entries, kvp->value);
387     }
388 }
389
390 static void
391 api_ip6_fib_table_get_all (unix_shared_memory_queue_t * q,
392                            vl_api_ip6_fib_dump_t * mp,
393                            fib_table_t * fib_table)
394 {
395   vpe_api_main_t *am = &vpe_api_main;
396   ip6_main_t *im6 = &ip6_main;
397   fib_node_index_t *fib_entry_index;
398   api_ip6_fib_show_ctx_t ctx = {
399     .fib_index = fib_table->ft_index,
400     .entries = NULL,
401   };
402   fib_route_path_encode_t *api_rpaths;
403   fib_prefix_t pfx;
404
405   BV (clib_bihash_foreach_key_value_pair)
406     ((BVT (clib_bihash) *) & im6->ip6_table[IP6_FIB_TABLE_NON_FWDING].
407      ip6_hash, api_ip6_fib_table_put_entries, &ctx);
408
409   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
410
411   vec_foreach (fib_entry_index, ctx.entries)
412   {
413     fib_entry_get_prefix (*fib_entry_index, &pfx);
414     api_rpaths = NULL;
415     fib_entry_encode (*fib_entry_index, &api_rpaths);
416     send_ip6_fib_details (am, q,
417                           fib_table->ft_table_id,
418                           &pfx, api_rpaths, mp->context);
419     vec_free (api_rpaths);
420   }
421
422   vec_free (ctx.entries);
423 }
424
425 static void
426 vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp)
427 {
428   unix_shared_memory_queue_t *q;
429   ip6_main_t *im6 = &ip6_main;
430   fib_table_t *fib_table;
431
432   q = vl_api_client_index_to_input_queue (mp->client_index);
433   if (q == 0)
434     return;
435
436   /* *INDENT-OFF* */
437   pool_foreach (fib_table, im6->fibs,
438   ({
439     api_ip6_fib_table_get_all(q, mp, fib_table);
440   }));
441   /* *INDENT-ON* */
442 }
443
444 static void
445 send_ip_mfib_details (unix_shared_memory_queue_t * q,
446                       u32 context, u32 table_id, fib_node_index_t mfei)
447 {
448   fib_route_path_encode_t *api_rpath, *api_rpaths = NULL;
449   vl_api_ip_mfib_details_t *mp;
450   mfib_entry_t *mfib_entry;
451   vl_api_fib_path_t *fp;
452   mfib_prefix_t pfx;
453   int path_count;
454
455   mfib_entry = mfib_entry_get (mfei);
456   mfib_entry_get_prefix (mfei, &pfx);
457   mfib_entry_encode (mfei, &api_rpaths);
458
459   path_count = vec_len (api_rpaths);
460   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
461   if (!mp)
462     return;
463   memset (mp, 0, sizeof (*mp));
464   mp->_vl_msg_id = ntohs (VL_API_IP_FIB_DETAILS);
465   mp->context = context;
466
467   mp->rpf_id = mfib_entry->mfe_rpf_id;
468   mp->entry_flags = mfib_entry->mfe_flags;
469   mp->table_id = htonl (table_id);
470   mp->address_length = pfx.fp_len;
471   memcpy (mp->grp_address, &pfx.fp_grp_addr.ip4,
472           sizeof (pfx.fp_grp_addr.ip4));
473   memcpy (mp->src_address, &pfx.fp_src_addr.ip4,
474           sizeof (pfx.fp_src_addr.ip4));
475
476   mp->count = htonl (path_count);
477   fp = mp->path;
478   vec_foreach (api_rpath, api_rpaths)
479   {
480     memset (fp, 0, sizeof (*fp));
481
482     fp->weight = 0;
483     fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
484     copy_fib_next_hop (api_rpath, fp);
485     fp++;
486   }
487   vec_free (api_rpaths);
488
489   vl_msg_api_send_shmem (q, (u8 *) & mp);
490 }
491
492 typedef struct vl_api_ip_mfib_dump_ctc_t_
493 {
494   fib_node_index_t *entries;
495 } vl_api_ip_mfib_dump_ctc_t;
496
497 static int
498 vl_api_ip_mfib_table_dump_walk (fib_node_index_t fei, void *arg)
499 {
500   vl_api_ip_mfib_dump_ctc_t *ctx = arg;
501
502   vec_add1 (ctx->entries, fei);
503
504   return (0);
505 }
506
507 static void
508 vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
509 {
510   unix_shared_memory_queue_t *q;
511   ip4_main_t *im = &ip4_main;
512   mfib_table_t *mfib_table;
513   fib_node_index_t *mfeip;
514   vl_api_ip_mfib_dump_ctc_t ctx = {
515     .entries = NULL,
516   };
517
518   q = vl_api_client_index_to_input_queue (mp->client_index);
519   if (q == 0)
520     return;
521
522
523   /* *INDENT-OFF* */
524   pool_foreach (mfib_table, im->mfibs,
525   ({
526     ip4_mfib_table_walk(&mfib_table->v4,
527                         vl_api_ip_mfib_table_dump_walk,
528                         &ctx);
529
530     vec_sort_with_function (ctx.entries, mfib_entry_cmp_for_sort);
531
532     vec_foreach (mfeip, ctx.entries)
533     {
534       send_ip_mfib_details (q, mp->context,
535                             mfib_table->mft_table_id,
536                             *mfeip);
537     }
538     vec_reset_length (ctx.entries);
539
540   }));
541   /* *INDENT-ON* */
542
543   vec_free (ctx.entries);
544 }
545
546 static void
547 send_ip6_mfib_details (vpe_api_main_t * am,
548                        unix_shared_memory_queue_t * q,
549                        u32 table_id,
550                        mfib_prefix_t * pfx,
551                        fib_route_path_encode_t * api_rpaths, u32 context)
552 {
553   vl_api_ip6_mfib_details_t *mp;
554   fib_route_path_encode_t *api_rpath;
555   vl_api_fib_path_t *fp;
556   int path_count;
557
558   path_count = vec_len (api_rpaths);
559   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
560   if (!mp)
561     return;
562   memset (mp, 0, sizeof (*mp));
563   mp->_vl_msg_id = ntohs (VL_API_IP6_FIB_DETAILS);
564   mp->context = context;
565
566   mp->table_id = htonl (table_id);
567   mp->address_length = pfx->fp_len;
568   memcpy (mp->grp_address, &pfx->fp_grp_addr.ip6,
569           sizeof (pfx->fp_grp_addr.ip6));
570   memcpy (mp->src_address, &pfx->fp_src_addr.ip6,
571           sizeof (pfx->fp_src_addr.ip6));
572
573   mp->count = htonl (path_count);
574   fp = mp->path;
575   vec_foreach (api_rpath, api_rpaths)
576   {
577     memset (fp, 0, sizeof (*fp));
578
579     fp->weight = 0;
580     fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
581     copy_fib_next_hop (api_rpath, fp);
582     fp++;
583   }
584
585   vl_msg_api_send_shmem (q, (u8 *) & mp);
586 }
587
588 typedef struct vl_api_ip6_mfib_dump_ctc_t_
589 {
590   fib_node_index_t *entries;
591 } vl_api_ip6_mfib_dump_ctc_t;
592
593 static int
594 vl_api_ip6_mfib_table_dump_walk (fib_node_index_t fei, void *arg)
595 {
596   vl_api_ip6_mfib_dump_ctc_t *ctx = arg;
597
598   vec_add1 (ctx->entries, fei);
599
600   return (0);
601 }
602
603 static void
604 vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp)
605 {
606   vpe_api_main_t *am = &vpe_api_main;
607   unix_shared_memory_queue_t *q;
608   ip6_main_t *im = &ip6_main;
609   mfib_table_t *mfib_table;
610   fib_node_index_t *mfeip;
611   mfib_prefix_t pfx;
612   fib_route_path_encode_t *api_rpaths = NULL;
613   vl_api_ip6_mfib_dump_ctc_t ctx = {
614     .entries = NULL,
615   };
616
617   q = vl_api_client_index_to_input_queue (mp->client_index);
618   if (q == 0)
619     return;
620
621
622   /* *INDENT-OFF* */
623   pool_foreach (mfib_table, im->mfibs,
624   ({
625     ip6_mfib_table_walk(&mfib_table->v6,
626                         vl_api_ip6_mfib_table_dump_walk,
627                         &ctx);
628
629     vec_sort_with_function (ctx.entries, mfib_entry_cmp_for_sort);
630
631     vec_foreach(mfeip, ctx.entries)
632     {
633       mfib_entry_get_prefix (*mfeip, &pfx);
634       mfib_entry_encode (*mfeip, &api_rpaths);
635       send_ip6_mfib_details (am, q,
636                              mfib_table->mft_table_id,
637                              &pfx, api_rpaths,
638                              mp->context);
639     }
640     vec_reset_length (api_rpaths);
641     vec_reset_length (ctx.entries);
642
643   }));
644   /* *INDENT-ON* */
645
646   vec_free (ctx.entries);
647   vec_free (api_rpaths);
648 }
649
650 static void
651 vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
652                                       vlib_main_t * vm)
653 {
654   vl_api_ip_neighbor_add_del_reply_t *rmp;
655   vnet_main_t *vnm = vnet_get_main ();
656   int rv = 0;
657
658   VALIDATE_SW_IF_INDEX (mp);
659
660   stats_dslock_with_hint (1 /* release hint */ , 7 /* tag */ );
661
662   /*
663    * there's no validation here of the ND/ARP entry being added.
664    * The expectation is that the FIB will ensure that nothing bad
665    * will come of adding bogus entries.
666    */
667   if (mp->is_ipv6)
668     {
669       if (mp->is_add)
670         rv = vnet_set_ip6_ethernet_neighbor
671           (vm, ntohl (mp->sw_if_index),
672            (ip6_address_t *) (mp->dst_address),
673            mp->mac_address, sizeof (mp->mac_address), mp->is_static,
674            mp->is_no_adj_fib);
675       else
676         rv = vnet_unset_ip6_ethernet_neighbor
677           (vm, ntohl (mp->sw_if_index),
678            (ip6_address_t *) (mp->dst_address),
679            mp->mac_address, sizeof (mp->mac_address));
680     }
681   else
682     {
683       ethernet_arp_ip4_over_ethernet_address_t a;
684
685       clib_memcpy (&a.ethernet, mp->mac_address, 6);
686       clib_memcpy (&a.ip4, mp->dst_address, 4);
687
688       if (mp->is_add)
689         rv = vnet_arp_set_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index),
690                                              &a, mp->is_static,
691                                              mp->is_no_adj_fib);
692       else
693         rv =
694           vnet_arp_unset_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index), &a);
695     }
696
697   BAD_SW_IF_INDEX_LABEL;
698
699   stats_dsunlock ();
700   REPLY_MACRO (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY);
701 }
702
703 void
704 ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api)
705 {
706   u32 fib_index, mfib_index;
707
708   /*
709    * ignore action on the default table - this is always present
710    * and cannot be added nor deleted from the API
711    */
712   if (0 != table_id)
713     {
714       /*
715        * The API holds only one lock on the table.
716        * i.e. it can be added many times via the API but needs to be
717        * deleted only once.
718        * The FIB index for unicast and multicast is not necessarily the
719        * same, since internal VPP systesm (like LISP and SR) create
720        * their own unicast tables.
721        */
722       fib_index = fib_table_find (fproto, table_id);
723       mfib_index = mfib_table_find (fproto, table_id);
724
725       if (~0 != fib_index)
726         {
727           fib_table_unlock (fib_index, fproto,
728                             (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI));
729         }
730       if (~0 != mfib_index)
731         {
732           mfib_table_unlock (mfib_index, fproto,
733                              (is_api ? MFIB_SOURCE_API : MFIB_SOURCE_CLI));
734         }
735     }
736 }
737
738 void
739 vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
740 {
741   vl_api_ip_table_add_del_reply_t *rmp;
742   fib_protocol_t fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
743   u32 table_id = ntohl (mp->table_id);
744   int rv = 0;
745
746   if (mp->is_add)
747     {
748       ip_table_create (fproto, table_id, 1, mp->name);
749     }
750   else
751     {
752       ip_table_delete (fproto, table_id, 1);
753     }
754
755   REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_REPLY);
756 }
757
758 int
759 add_del_route_t_handler (u8 is_multipath,
760                          u8 is_add,
761                          u8 is_drop,
762                          u8 is_unreach,
763                          u8 is_prohibit,
764                          u8 is_local,
765                          u8 is_multicast,
766                          u8 is_classify,
767                          u32 classify_table_index,
768                          u8 is_resolve_host,
769                          u8 is_resolve_attached,
770                          u8 is_interface_rx,
771                          u8 is_rpf_id,
772                          u32 fib_index,
773                          const fib_prefix_t * prefix,
774                          dpo_proto_t next_hop_proto,
775                          const ip46_address_t * next_hop,
776                          u32 next_hop_sw_if_index,
777                          u8 next_hop_fib_index,
778                          u16 next_hop_weight,
779                          u16 next_hop_preference,
780                          mpls_label_t next_hop_via_label,
781                          mpls_label_t * next_hop_out_label_stack)
782 {
783   vnet_classify_main_t *cm = &vnet_classify_main;
784   fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
785   fib_route_path_t path = {
786     .frp_proto = next_hop_proto,
787     .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
788     .frp_sw_if_index = next_hop_sw_if_index,
789     .frp_fib_index = next_hop_fib_index,
790     .frp_weight = next_hop_weight,
791     .frp_preference = next_hop_preference,
792     .frp_label_stack = next_hop_out_label_stack,
793   };
794   fib_route_path_t *paths = NULL;
795   fib_entry_flag_t entry_flags = FIB_ENTRY_FLAG_NONE;
796
797   if (MPLS_LABEL_INVALID != next_hop_via_label)
798     {
799       path.frp_proto = DPO_PROTO_MPLS;
800       path.frp_local_label = next_hop_via_label;
801       path.frp_eos = MPLS_NON_EOS;
802     }
803   if (is_resolve_host)
804     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
805   if (is_resolve_attached)
806     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
807   if (is_interface_rx)
808     path_flags |= FIB_ROUTE_PATH_INTF_RX;
809   if (is_rpf_id)
810     path_flags |= FIB_ROUTE_PATH_RPF_ID;
811   if (is_multicast)
812     entry_flags |= FIB_ENTRY_FLAG_MULTICAST;
813
814   path.frp_flags = path_flags;
815
816   if (is_multipath)
817     {
818       stats_dslock_with_hint (1 /* release hint */ , 10 /* tag */ );
819
820
821       vec_add1 (paths, path);
822
823       if (is_add)
824         fib_table_entry_path_add2 (fib_index,
825                                    prefix,
826                                    FIB_SOURCE_API, entry_flags, paths);
827       else
828         fib_table_entry_path_remove2 (fib_index,
829                                       prefix, FIB_SOURCE_API, paths);
830
831       vec_free (paths);
832       stats_dsunlock ();
833       return 0;
834     }
835
836   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
837
838   if (is_drop || is_local || is_classify || is_unreach || is_prohibit)
839     {
840       /*
841        * special route types that link directly to the adj
842        */
843       if (is_add)
844         {
845           dpo_id_t dpo = DPO_INVALID;
846           dpo_proto_t dproto;
847
848           dproto = fib_proto_to_dpo (prefix->fp_proto);
849
850           if (is_drop)
851             ip_null_dpo_add_and_lock (dproto, IP_NULL_ACTION_NONE, &dpo);
852           else if (is_local)
853             receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo);
854           else if (is_unreach)
855             ip_null_dpo_add_and_lock (dproto,
856                                       IP_NULL_ACTION_SEND_ICMP_UNREACH, &dpo);
857           else if (is_prohibit)
858             ip_null_dpo_add_and_lock (dproto,
859                                       IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
860                                       &dpo);
861           else if (is_classify)
862             {
863               if (pool_is_free_index (cm->tables,
864                                       ntohl (classify_table_index)))
865                 {
866                   stats_dsunlock ();
867                   return VNET_API_ERROR_NO_SUCH_TABLE;
868                 }
869
870               dpo_set (&dpo, DPO_CLASSIFY, dproto,
871                        classify_dpo_create (dproto,
872                                             ntohl (classify_table_index)));
873             }
874           else
875             {
876               stats_dsunlock ();
877               return VNET_API_ERROR_NO_SUCH_TABLE;
878             }
879
880           fib_table_entry_special_dpo_update (fib_index,
881                                               prefix,
882                                               FIB_SOURCE_API,
883                                               FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
884           dpo_reset (&dpo);
885         }
886       else
887         {
888           fib_table_entry_special_remove (fib_index, prefix, FIB_SOURCE_API);
889         }
890     }
891   else
892     {
893       if (is_add)
894         {
895           vec_add1 (paths, path);
896           fib_table_entry_update (fib_index,
897                                   prefix, FIB_SOURCE_API, entry_flags, paths);
898           vec_free (paths);
899         }
900       else
901         {
902           fib_table_entry_delete (fib_index, prefix, FIB_SOURCE_API);
903         }
904     }
905
906   stats_dsunlock ();
907   return (0);
908 }
909
910 int
911 add_del_route_check (fib_protocol_t table_proto,
912                      u32 table_id,
913                      u32 next_hop_sw_if_index,
914                      dpo_proto_t next_hop_table_proto,
915                      u32 next_hop_table_id,
916                      u8 is_rpf_id, u32 * fib_index, u32 * next_hop_fib_index)
917 {
918   vnet_main_t *vnm = vnet_get_main ();
919
920   /* Temporaray whilst I do the CSIT dance */
921   u8 create_missing_tables = 1;
922
923   *fib_index = fib_table_find (table_proto, ntohl (table_id));
924   if (~0 == *fib_index)
925     {
926       if (create_missing_tables)
927         {
928           *fib_index = fib_table_find_or_create_and_lock (table_proto,
929                                                           ntohl (table_id),
930                                                           FIB_SOURCE_API);
931         }
932       else
933         {
934           /* No such VRF, and we weren't asked to create one */
935           return VNET_API_ERROR_NO_SUCH_FIB;
936         }
937     }
938
939   if (!is_rpf_id && ~0 != ntohl (next_hop_sw_if_index))
940     {
941       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
942                               ntohl (next_hop_sw_if_index)))
943         {
944           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
945         }
946     }
947   else
948     {
949       fib_protocol_t fib_nh_proto;
950
951       if (next_hop_table_proto > DPO_PROTO_MPLS)
952         return (0);
953
954       fib_nh_proto = dpo_proto_to_fib (next_hop_table_proto);
955
956       if (is_rpf_id)
957         *next_hop_fib_index = mfib_table_find (fib_nh_proto,
958                                                ntohl (next_hop_table_id));
959       else
960         *next_hop_fib_index = fib_table_find (fib_nh_proto,
961                                               ntohl (next_hop_table_id));
962
963       if (~0 == *next_hop_fib_index)
964         {
965           if (create_missing_tables)
966             {
967               if (is_rpf_id)
968                 *next_hop_fib_index =
969                   mfib_table_find_or_create_and_lock (fib_nh_proto,
970                                                       ntohl
971                                                       (next_hop_table_id),
972                                                       MFIB_SOURCE_API);
973               else
974                 *next_hop_fib_index =
975                   fib_table_find_or_create_and_lock (fib_nh_proto,
976                                                      ntohl
977                                                      (next_hop_table_id),
978                                                      FIB_SOURCE_API);
979             }
980           else
981             {
982               /* No such VRF, and we weren't asked to create one */
983               return VNET_API_ERROR_NO_SUCH_FIB;
984             }
985         }
986     }
987
988   return (0);
989 }
990
991 static int
992 ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
993 {
994   u32 fib_index, next_hop_fib_index;
995   mpls_label_t *label_stack = NULL;
996   int rv, ii, n_labels;;
997
998   rv = add_del_route_check (FIB_PROTOCOL_IP4,
999                             mp->table_id,
1000                             mp->next_hop_sw_if_index,
1001                             DPO_PROTO_IP4,
1002                             mp->next_hop_table_id,
1003                             0, &fib_index, &next_hop_fib_index);
1004
1005   if (0 != rv)
1006     return (rv);
1007
1008   fib_prefix_t pfx = {
1009     .fp_len = mp->dst_address_length,
1010     .fp_proto = FIB_PROTOCOL_IP4,
1011   };
1012   clib_memcpy (&pfx.fp_addr.ip4, mp->dst_address, sizeof (pfx.fp_addr.ip4));
1013
1014   ip46_address_t nh;
1015   memset (&nh, 0, sizeof (nh));
1016   memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4));
1017
1018   n_labels = mp->next_hop_n_out_labels;
1019   if (n_labels == 0)
1020     ;
1021   else if (1 == n_labels)
1022     vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
1023   else
1024     {
1025       vec_validate (label_stack, n_labels - 1);
1026       for (ii = 0; ii < n_labels; ii++)
1027         label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
1028     }
1029
1030   return (add_del_route_t_handler (mp->is_multipath,
1031                                    mp->is_add,
1032                                    mp->is_drop,
1033                                    mp->is_unreach,
1034                                    mp->is_prohibit,
1035                                    mp->is_local, 0,
1036                                    mp->is_classify,
1037                                    mp->classify_table_index,
1038                                    mp->is_resolve_host,
1039                                    mp->is_resolve_attached, 0, 0,
1040                                    fib_index, &pfx, DPO_PROTO_IP4,
1041                                    &nh,
1042                                    ntohl (mp->next_hop_sw_if_index),
1043                                    next_hop_fib_index,
1044                                    mp->next_hop_weight,
1045                                    mp->next_hop_preference,
1046                                    ntohl (mp->next_hop_via_label),
1047                                    label_stack));
1048 }
1049
1050 static int
1051 ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
1052 {
1053   u32 fib_index, next_hop_fib_index;
1054   mpls_label_t *label_stack = NULL;
1055   int rv, ii, n_labels;;
1056
1057   rv = add_del_route_check (FIB_PROTOCOL_IP6,
1058                             mp->table_id,
1059                             mp->next_hop_sw_if_index,
1060                             DPO_PROTO_IP6,
1061                             mp->next_hop_table_id,
1062                             0, &fib_index, &next_hop_fib_index);
1063
1064   if (0 != rv)
1065     return (rv);
1066
1067   fib_prefix_t pfx = {
1068     .fp_len = mp->dst_address_length,
1069     .fp_proto = FIB_PROTOCOL_IP6,
1070   };
1071   clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6));
1072
1073   ip46_address_t nh;
1074   memset (&nh, 0, sizeof (nh));
1075   memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6));
1076
1077   n_labels = mp->next_hop_n_out_labels;
1078   if (n_labels == 0)
1079     ;
1080   else if (1 == n_labels)
1081     vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
1082   else
1083     {
1084       vec_validate (label_stack, n_labels - 1);
1085       for (ii = 0; ii < n_labels; ii++)
1086         label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
1087     }
1088
1089   return (add_del_route_t_handler (mp->is_multipath,
1090                                    mp->is_add,
1091                                    mp->is_drop,
1092                                    mp->is_unreach,
1093                                    mp->is_prohibit,
1094                                    mp->is_local, 0,
1095                                    mp->is_classify,
1096                                    mp->classify_table_index,
1097                                    mp->is_resolve_host,
1098                                    mp->is_resolve_attached, 0, 0,
1099                                    fib_index, &pfx, DPO_PROTO_IP6,
1100                                    &nh, ntohl (mp->next_hop_sw_if_index),
1101                                    next_hop_fib_index,
1102                                    mp->next_hop_weight,
1103                                    mp->next_hop_preference,
1104                                    ntohl (mp->next_hop_via_label),
1105                                    label_stack));
1106 }
1107
1108 void
1109 vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
1110 {
1111   vl_api_ip_add_del_route_reply_t *rmp;
1112   int rv;
1113   vnet_main_t *vnm = vnet_get_main ();
1114
1115   vnm->api_errno = 0;
1116
1117   if (mp->is_ipv6)
1118     rv = ip6_add_del_route_t_handler (mp);
1119   else
1120     rv = ip4_add_del_route_t_handler (mp);
1121
1122   rv = (rv == 0) ? vnm->api_errno : rv;
1123
1124   REPLY_MACRO (VL_API_IP_ADD_DEL_ROUTE_REPLY);
1125 }
1126
1127 void
1128 ip_table_create (fib_protocol_t fproto,
1129                  u32 table_id, u8 is_api, const u8 * name)
1130 {
1131   u32 fib_index, mfib_index;
1132
1133   /*
1134    * ignore action on the default table - this is always present
1135    * and cannot be added nor deleted from the API
1136    */
1137   if (0 != table_id)
1138     {
1139       /*
1140        * The API holds only one lock on the table.
1141        * i.e. it can be added many times via the API but needs to be
1142        * deleted only once.
1143        * The FIB index for unicast and multicast is not necessarily the
1144        * same, since internal VPP systesm (like LISP and SR) create
1145        * their own unicast tables.
1146        */
1147       fib_index = fib_table_find (fproto, table_id);
1148       mfib_index = mfib_table_find (fproto, table_id);
1149
1150       if (~0 == fib_index)
1151         {
1152           fib_table_find_or_create_and_lock_w_name (fproto, table_id,
1153                                                     (is_api ?
1154                                                      FIB_SOURCE_API :
1155                                                      FIB_SOURCE_CLI), name);
1156         }
1157       if (~0 == mfib_index)
1158         {
1159           mfib_table_find_or_create_and_lock_w_name (fproto, table_id,
1160                                                      (is_api ?
1161                                                       MFIB_SOURCE_API :
1162                                                       MFIB_SOURCE_CLI), name);
1163         }
1164     }
1165 }
1166
1167 static int
1168 add_del_mroute_check (fib_protocol_t table_proto,
1169                       u32 table_id,
1170                       u32 next_hop_sw_if_index, u8 is_local, u32 * fib_index)
1171 {
1172   vnet_main_t *vnm = vnet_get_main ();
1173
1174   *fib_index = mfib_table_find (table_proto, ntohl (table_id));
1175   if (~0 == *fib_index)
1176     {
1177       /* No such table */
1178       return VNET_API_ERROR_NO_SUCH_FIB;
1179     }
1180
1181   if (~0 != ntohl (next_hop_sw_if_index))
1182     {
1183       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
1184                               ntohl (next_hop_sw_if_index)))
1185         {
1186           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
1187         }
1188     }
1189
1190   return (0);
1191 }
1192
1193 static int
1194 mroute_add_del_handler (u8 is_add,
1195                         u8 is_local,
1196                         u32 fib_index,
1197                         const mfib_prefix_t * prefix,
1198                         u32 entry_flags,
1199                         fib_rpf_id_t rpf_id,
1200                         u32 next_hop_sw_if_index, u32 itf_flags)
1201 {
1202   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
1203
1204   fib_route_path_t path = {
1205     .frp_sw_if_index = next_hop_sw_if_index,
1206     .frp_proto = fib_proto_to_dpo (prefix->fp_proto),
1207   };
1208
1209   if (is_local)
1210     path.frp_flags |= FIB_ROUTE_PATH_LOCAL;
1211
1212
1213   if (!is_local && ~0 == next_hop_sw_if_index)
1214     {
1215       mfib_table_entry_update (fib_index, prefix,
1216                                MFIB_SOURCE_API, rpf_id, entry_flags);
1217     }
1218   else
1219     {
1220       if (is_add)
1221         {
1222           mfib_table_entry_path_update (fib_index, prefix,
1223                                         MFIB_SOURCE_API, &path, itf_flags);
1224         }
1225       else
1226         {
1227           mfib_table_entry_path_remove (fib_index, prefix,
1228                                         MFIB_SOURCE_API, &path);
1229         }
1230     }
1231
1232   stats_dsunlock ();
1233   return (0);
1234 }
1235
1236 static int
1237 api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
1238 {
1239   fib_protocol_t fproto;
1240   u32 fib_index;
1241   int rv;
1242
1243   fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1244   rv = add_del_mroute_check (fproto,
1245                              mp->table_id,
1246                              mp->next_hop_sw_if_index,
1247                              mp->is_local, &fib_index);
1248
1249   if (0 != rv)
1250     return (rv);
1251
1252   mfib_prefix_t pfx = {
1253     .fp_len = ntohs (mp->grp_address_length),
1254     .fp_proto = fproto,
1255   };
1256
1257   if (FIB_PROTOCOL_IP4 == fproto)
1258     {
1259       clib_memcpy (&pfx.fp_grp_addr.ip4, mp->grp_address,
1260                    sizeof (pfx.fp_grp_addr.ip4));
1261       clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address,
1262                    sizeof (pfx.fp_src_addr.ip4));
1263     }
1264   else
1265     {
1266       clib_memcpy (&pfx.fp_grp_addr.ip6, mp->grp_address,
1267                    sizeof (pfx.fp_grp_addr.ip6));
1268       clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address,
1269                    sizeof (pfx.fp_src_addr.ip6));
1270     }
1271
1272   return (mroute_add_del_handler (mp->is_add,
1273                                   mp->is_local,
1274                                   fib_index, &pfx,
1275                                   ntohl (mp->entry_flags),
1276                                   ntohl (mp->rpf_id),
1277                                   ntohl (mp->next_hop_sw_if_index),
1278                                   ntohl (mp->itf_flags)));
1279 }
1280
1281 void
1282 vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
1283 {
1284   vl_api_ip_mroute_add_del_reply_t *rmp;
1285   int rv;
1286   vnet_main_t *vnm = vnet_get_main ();
1287
1288   vnm->api_errno = 0;
1289
1290   rv = api_mroute_add_del_t_handler (mp);
1291
1292   rv = (rv == 0) ? vnm->api_errno : rv;
1293
1294   REPLY_MACRO (VL_API_IP_MROUTE_ADD_DEL_REPLY);
1295 }
1296
1297 static void
1298 send_ip_details (vpe_api_main_t * am,
1299                  unix_shared_memory_queue_t * q, u32 sw_if_index,
1300                  u8 is_ipv6, u32 context)
1301 {
1302   vl_api_ip_details_t *mp;
1303
1304   mp = vl_msg_api_alloc (sizeof (*mp));
1305   memset (mp, 0, sizeof (*mp));
1306   mp->_vl_msg_id = ntohs (VL_API_IP_DETAILS);
1307
1308   mp->sw_if_index = ntohl (sw_if_index);
1309   mp->is_ipv6 = is_ipv6;
1310   mp->context = context;
1311
1312   vl_msg_api_send_shmem (q, (u8 *) & mp);
1313 }
1314
1315 static void
1316 send_ip_address_details (vpe_api_main_t * am,
1317                          unix_shared_memory_queue_t * q,
1318                          u8 * ip, u16 prefix_length,
1319                          u32 sw_if_index, u8 is_ipv6, u32 context)
1320 {
1321   vl_api_ip_address_details_t *mp;
1322
1323   mp = vl_msg_api_alloc (sizeof (*mp));
1324   memset (mp, 0, sizeof (*mp));
1325   mp->_vl_msg_id = ntohs (VL_API_IP_ADDRESS_DETAILS);
1326
1327   if (is_ipv6)
1328     {
1329       clib_memcpy (&mp->ip, ip, sizeof (mp->ip));
1330     }
1331   else
1332     {
1333       u32 *tp = (u32 *) mp->ip;
1334       *tp = *(u32 *) ip;
1335     }
1336   mp->prefix_length = prefix_length;
1337   mp->context = context;
1338   mp->sw_if_index = htonl (sw_if_index);
1339   mp->is_ipv6 = is_ipv6;
1340
1341   vl_msg_api_send_shmem (q, (u8 *) & mp);
1342 }
1343
1344 static void
1345 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
1346 {
1347   vpe_api_main_t *am = &vpe_api_main;
1348   unix_shared_memory_queue_t *q;
1349   ip6_address_t *r6;
1350   ip4_address_t *r4;
1351   ip6_main_t *im6 = &ip6_main;
1352   ip4_main_t *im4 = &ip4_main;
1353   ip_lookup_main_t *lm6 = &im6->lookup_main;
1354   ip_lookup_main_t *lm4 = &im4->lookup_main;
1355   ip_interface_address_t *ia = 0;
1356   u32 sw_if_index = ~0;
1357   int rv __attribute__ ((unused)) = 0;
1358
1359   VALIDATE_SW_IF_INDEX (mp);
1360
1361   sw_if_index = ntohl (mp->sw_if_index);
1362
1363   q = vl_api_client_index_to_input_queue (mp->client_index);
1364   if (q == 0)
1365     return;
1366
1367   if (mp->is_ipv6)
1368     {
1369       /* *INDENT-OFF* */
1370       foreach_ip_interface_address (lm6, ia, sw_if_index,
1371                                     1 /* honor unnumbered */,
1372       ({
1373         r6 = ip_interface_address_get_address (lm6, ia);
1374         u16 prefix_length = ia->address_length;
1375         send_ip_address_details(am, q, (u8*)r6, prefix_length,
1376                                 sw_if_index, 1, mp->context);
1377       }));
1378       /* *INDENT-ON* */
1379     }
1380   else
1381     {
1382       /* *INDENT-OFF* */
1383       foreach_ip_interface_address (lm4, ia, sw_if_index,
1384                                     1 /* honor unnumbered */,
1385       ({
1386         r4 = ip_interface_address_get_address (lm4, ia);
1387         u16 prefix_length = ia->address_length;
1388         send_ip_address_details(am, q, (u8*)r4, prefix_length,
1389                                 sw_if_index, 0, mp->context);
1390       }));
1391       /* *INDENT-ON* */
1392     }
1393   BAD_SW_IF_INDEX_LABEL;
1394 }
1395
1396 static void
1397 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
1398 {
1399   vpe_api_main_t *am = &vpe_api_main;
1400   vnet_main_t *vnm = vnet_get_main ();
1401   vlib_main_t *vm = vlib_get_main ();
1402   vnet_interface_main_t *im = &vnm->interface_main;
1403   unix_shared_memory_queue_t *q;
1404   vnet_sw_interface_t *si, *sorted_sis;
1405   u32 sw_if_index = ~0;
1406
1407   q = vl_api_client_index_to_input_queue (mp->client_index);
1408   if (q == 0)
1409     {
1410       return;
1411     }
1412
1413   /* Gather interfaces. */
1414   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1415   _vec_len (sorted_sis) = 0;
1416   /* *INDENT-OFF* */
1417   pool_foreach (si, im->sw_interfaces,
1418   ({
1419     vec_add1 (sorted_sis, si[0]);
1420   }));
1421   /* *INDENT-ON* */
1422
1423   vec_foreach (si, sorted_sis)
1424   {
1425     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1426       {
1427         if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index))
1428           {
1429             continue;
1430           }
1431         sw_if_index = si->sw_if_index;
1432         send_ip_details (am, q, sw_if_index, mp->is_ipv6, mp->context);
1433       }
1434   }
1435 }
1436
1437 static void
1438 set_ip6_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1439 {
1440   vl_api_set_ip_flow_hash_reply_t *rmp;
1441   int rv;
1442   u32 table_id;
1443   flow_hash_config_t flow_hash_config = 0;
1444
1445   table_id = ntohl (mp->vrf_id);
1446
1447 #define _(a,b) if (mp->a) flow_hash_config |= b;
1448   foreach_flow_hash_bit;
1449 #undef _
1450
1451   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
1452
1453   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1454 }
1455
1456 static void
1457 set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1458 {
1459   vl_api_set_ip_flow_hash_reply_t *rmp;
1460   int rv;
1461   u32 table_id;
1462   flow_hash_config_t flow_hash_config = 0;
1463
1464   table_id = ntohl (mp->vrf_id);
1465
1466 #define _(a,b) if (mp->a) flow_hash_config |= b;
1467   foreach_flow_hash_bit;
1468 #undef _
1469
1470   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
1471
1472   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1473 }
1474
1475
1476 static void
1477 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t * mp)
1478 {
1479   if (mp->is_ipv6 == 0)
1480     set_ip4_flow_hash (mp);
1481   else
1482     set_ip6_flow_hash (mp);
1483 }
1484
1485 static void
1486   vl_api_sw_interface_ip6nd_ra_config_t_handler
1487   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
1488 {
1489   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
1490   vlib_main_t *vm = vlib_get_main ();
1491   int rv = 0;
1492   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
1493     default_router;
1494
1495   is_no = mp->is_no == 1;
1496   suppress = mp->suppress == 1;
1497   managed = mp->managed == 1;
1498   other = mp->other == 1;
1499   ll_option = mp->ll_option == 1;
1500   send_unicast = mp->send_unicast == 1;
1501   cease = mp->cease == 1;
1502   default_router = mp->default_router == 1;
1503
1504   VALIDATE_SW_IF_INDEX (mp);
1505
1506   rv = ip6_neighbor_ra_config (vm, ntohl (mp->sw_if_index),
1507                                suppress, managed, other,
1508                                ll_option, send_unicast, cease,
1509                                default_router, ntohl (mp->lifetime),
1510                                ntohl (mp->initial_count),
1511                                ntohl (mp->initial_interval),
1512                                ntohl (mp->max_interval),
1513                                ntohl (mp->min_interval), is_no);
1514
1515   BAD_SW_IF_INDEX_LABEL;
1516
1517   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
1518 }
1519
1520 static void
1521   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
1522   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
1523 {
1524   vlib_main_t *vm = vlib_get_main ();
1525   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
1526   int rv = 0;
1527   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
1528
1529   VALIDATE_SW_IF_INDEX (mp);
1530
1531   is_no = mp->is_no == 1;
1532   use_default = mp->use_default == 1;
1533   no_advertise = mp->no_advertise == 1;
1534   off_link = mp->off_link == 1;
1535   no_autoconfig = mp->no_autoconfig == 1;
1536   no_onlink = mp->no_onlink == 1;
1537
1538   rv = ip6_neighbor_ra_prefix (vm, ntohl (mp->sw_if_index),
1539                                (ip6_address_t *) mp->address,
1540                                mp->address_length, use_default,
1541                                ntohl (mp->val_lifetime),
1542                                ntohl (mp->pref_lifetime), no_advertise,
1543                                off_link, no_autoconfig, no_onlink, is_no);
1544
1545   BAD_SW_IF_INDEX_LABEL;
1546   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
1547 }
1548
1549 static void
1550 send_ip6nd_proxy_details (unix_shared_memory_queue_t * q,
1551                           u32 context,
1552                           const ip46_address_t * addr, u32 sw_if_index)
1553 {
1554   vl_api_ip6nd_proxy_details_t *mp;
1555
1556   mp = vl_msg_api_alloc (sizeof (*mp));
1557   memset (mp, 0, sizeof (*mp));
1558   mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
1559   mp->context = context;
1560   mp->sw_if_index = htonl (sw_if_index);
1561   memcpy (mp->address, addr, 16);
1562
1563   vl_msg_api_send_shmem (q, (u8 *) & mp);
1564 }
1565
1566 typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
1567 {
1568   u32 *indices;
1569 } api_ip6nd_proxy_fib_table_walk_ctx_t;
1570
1571 static int
1572 api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
1573 {
1574   api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
1575
1576   if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
1577     {
1578       vec_add1 (ctx->indices, fei);
1579     }
1580
1581   return (1);
1582 }
1583
1584 static void
1585 vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
1586 {
1587   ip6_main_t *im6 = &ip6_main;
1588   fib_table_t *fib_table;
1589   api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
1590     .indices = NULL,
1591   };
1592   fib_node_index_t *feip;
1593   fib_prefix_t pfx;
1594   unix_shared_memory_queue_t *q;
1595
1596   q = vl_api_client_index_to_input_queue (mp->client_index);
1597   if (q == 0)
1598     {
1599       return;
1600     }
1601
1602   /* *INDENT-OFF* */
1603   pool_foreach (fib_table, im6->fibs,
1604   ({
1605     fib_table_walk(fib_table->ft_index,
1606                    FIB_PROTOCOL_IP6,
1607                    api_ip6nd_proxy_fib_table_walk,
1608                    &ctx);
1609   }));
1610   /* *INDENT-ON* */
1611
1612   vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
1613
1614   vec_foreach (feip, ctx.indices)
1615   {
1616     fib_entry_get_prefix (*feip, &pfx);
1617
1618     send_ip6nd_proxy_details (q,
1619                               mp->context,
1620                               &pfx.fp_addr,
1621                               fib_entry_get_resolving_interface (*feip));
1622   }
1623
1624   vec_free (ctx.indices);
1625 }
1626
1627 static void
1628 vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
1629 {
1630   vl_api_ip6nd_proxy_add_del_reply_t *rmp;
1631   int rv = 0;
1632
1633   VALIDATE_SW_IF_INDEX (mp);
1634
1635   rv = ip6_neighbor_proxy_add_del (ntohl (mp->sw_if_index),
1636                                    (ip6_address_t *) mp->address, mp->is_del);
1637
1638   BAD_SW_IF_INDEX_LABEL;
1639   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
1640 }
1641
1642 static void
1643   vl_api_sw_interface_ip6_enable_disable_t_handler
1644   (vl_api_sw_interface_ip6_enable_disable_t * mp)
1645 {
1646   vlib_main_t *vm = vlib_get_main ();
1647   vl_api_sw_interface_ip6_enable_disable_reply_t *rmp;
1648   vnet_main_t *vnm = vnet_get_main ();
1649   int rv = 0;
1650   clib_error_t *error;
1651
1652   vnm->api_errno = 0;
1653
1654   VALIDATE_SW_IF_INDEX (mp);
1655
1656   error =
1657     (mp->enable == 1) ? enable_ip6_interface (vm,
1658                                               ntohl (mp->sw_if_index)) :
1659     disable_ip6_interface (vm, ntohl (mp->sw_if_index));
1660
1661   if (error)
1662     {
1663       clib_error_report (error);
1664       rv = VNET_API_ERROR_UNSPECIFIED;
1665     }
1666   else
1667     {
1668       rv = vnm->api_errno;
1669     }
1670
1671   BAD_SW_IF_INDEX_LABEL;
1672
1673   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
1674 }
1675
1676 static void
1677   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1678   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1679 {
1680   vlib_main_t *vm = vlib_get_main ();
1681   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1682   int rv = 0;
1683   clib_error_t *error;
1684   vnet_main_t *vnm = vnet_get_main ();
1685
1686   vnm->api_errno = 0;
1687
1688   VALIDATE_SW_IF_INDEX (mp);
1689
1690   error = set_ip6_link_local_address (vm,
1691                                       ntohl (mp->sw_if_index),
1692                                       (ip6_address_t *) mp->address);
1693   if (error)
1694     {
1695       clib_error_report (error);
1696       rv = VNET_API_ERROR_UNSPECIFIED;
1697     }
1698   else
1699     {
1700       rv = vnm->api_errno;
1701     }
1702
1703   BAD_SW_IF_INDEX_LABEL;
1704
1705   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1706 }
1707
1708 void
1709 vl_mfib_signal_send_one (unix_shared_memory_queue_t * q,
1710                          u32 context, const mfib_signal_t * mfs)
1711 {
1712   vl_api_mfib_signal_details_t *mp;
1713   mfib_prefix_t prefix;
1714   mfib_table_t *mfib;
1715   mfib_itf_t *mfi;
1716
1717   mp = vl_msg_api_alloc (sizeof (*mp));
1718
1719   memset (mp, 0, sizeof (*mp));
1720   mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS);
1721   mp->context = context;
1722
1723   mfi = mfib_itf_get (mfs->mfs_itf);
1724   mfib_entry_get_prefix (mfs->mfs_entry, &prefix);
1725   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1726                          prefix.fp_proto);
1727   mp->table_id = ntohl (mfib->mft_table_id);
1728   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1729
1730   if (FIB_PROTOCOL_IP4 == prefix.fp_proto)
1731     {
1732       mp->grp_address_len = ntohs (prefix.fp_len);
1733
1734       memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4);
1735       if (prefix.fp_len > 32)
1736         {
1737           memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4);
1738         }
1739     }
1740   else
1741     {
1742       mp->grp_address_len = ntohs (prefix.fp_len);
1743
1744       ASSERT (0);
1745     }
1746
1747   if (0 != mfs->mfs_buffer_len)
1748     {
1749       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1750
1751       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1752     }
1753   else
1754     {
1755       mp->ip_packet_len = 0;
1756     }
1757
1758   vl_msg_api_send_shmem (q, (u8 *) & mp);
1759 }
1760
1761 static void
1762 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1763 {
1764   unix_shared_memory_queue_t *q;
1765
1766   q = vl_api_client_index_to_input_queue (mp->client_index);
1767   if (q == 0)
1768     {
1769       return;
1770     }
1771
1772   while (q->cursize < q->maxsize && mfib_signal_send_one (q, mp->context))
1773     ;
1774 }
1775
1776 #define vl_msg_name_crc_list
1777 #include <vnet/ip/ip.api.h>
1778 #undef vl_msg_name_crc_list
1779
1780 static void
1781 setup_message_id_table (api_main_t * am)
1782 {
1783 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1784   foreach_vl_msg_name_crc_ip;
1785 #undef _
1786 }
1787
1788 static clib_error_t *
1789 ip_api_hookup (vlib_main_t * vm)
1790 {
1791   api_main_t *am = &api_main;
1792
1793 #define _(N,n)                                                  \
1794     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1795                            vl_api_##n##_t_handler,              \
1796                            vl_noop_handler,                     \
1797                            vl_api_##n##_t_endian,               \
1798                            vl_api_##n##_t_print,                \
1799                            sizeof(vl_api_##n##_t), 1);
1800   foreach_ip_api_msg;
1801 #undef _
1802
1803   /*
1804    * Set up the (msg_name, crc, message-id) table
1805    */
1806   setup_message_id_table (am);
1807
1808   return 0;
1809 }
1810
1811 VLIB_API_INIT_FUNCTION (ip_api_hookup);
1812
1813 /*
1814  * fd.io coding-style-patch-verification: ON
1815  *
1816  * Local Variables:
1817  * eval: (c-set-style "gnu")
1818  * End:
1819  */