IP neighbour move incorrectly placed jump label
[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   stats_dsunlock ();
698
699   BAD_SW_IF_INDEX_LABEL;
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                          u8 is_l2_bridged,
773                          u32 fib_index,
774                          const fib_prefix_t * prefix,
775                          dpo_proto_t next_hop_proto,
776                          const ip46_address_t * next_hop,
777                          u32 next_hop_sw_if_index,
778                          u8 next_hop_fib_index,
779                          u16 next_hop_weight,
780                          u16 next_hop_preference,
781                          mpls_label_t next_hop_via_label,
782                          mpls_label_t * next_hop_out_label_stack)
783 {
784   vnet_classify_main_t *cm = &vnet_classify_main;
785   fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
786   fib_route_path_t path = {
787     .frp_proto = next_hop_proto,
788     .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
789     .frp_sw_if_index = next_hop_sw_if_index,
790     .frp_fib_index = next_hop_fib_index,
791     .frp_weight = next_hop_weight,
792     .frp_preference = next_hop_preference,
793     .frp_label_stack = next_hop_out_label_stack,
794   };
795   fib_route_path_t *paths = NULL;
796   fib_entry_flag_t entry_flags = FIB_ENTRY_FLAG_NONE;
797
798   /*
799    * the special INVALID label meams we are not recursing via a
800    * label. Exp-null value is never a valid via-label so that
801    * also means it's not a via-label and means clients that set
802    * it to 0 by default get the expected behaviour
803    */
804   if ((MPLS_LABEL_INVALID != next_hop_via_label) && (0 != next_hop_via_label))
805     {
806       path.frp_proto = DPO_PROTO_MPLS;
807       path.frp_local_label = next_hop_via_label;
808       path.frp_eos = MPLS_NON_EOS;
809     }
810   if (is_l2_bridged)
811     path.frp_proto = DPO_PROTO_ETHERNET;
812   if (is_resolve_host)
813     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
814   if (is_resolve_attached)
815     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
816   if (is_interface_rx)
817     path_flags |= FIB_ROUTE_PATH_INTF_RX;
818   if (is_rpf_id)
819     path_flags |= FIB_ROUTE_PATH_RPF_ID;
820   if (is_multicast)
821     entry_flags |= FIB_ENTRY_FLAG_MULTICAST;
822
823   path.frp_flags = path_flags;
824
825   if (is_multipath)
826     {
827       stats_dslock_with_hint (1 /* release hint */ , 10 /* tag */ );
828
829
830       vec_add1 (paths, path);
831
832       if (is_add)
833         fib_table_entry_path_add2 (fib_index,
834                                    prefix,
835                                    FIB_SOURCE_API, entry_flags, paths);
836       else
837         fib_table_entry_path_remove2 (fib_index,
838                                       prefix, FIB_SOURCE_API, paths);
839
840       vec_free (paths);
841       stats_dsunlock ();
842       return 0;
843     }
844
845   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
846
847   if (is_drop || is_local || is_classify || is_unreach || is_prohibit)
848     {
849       /*
850        * special route types that link directly to the adj
851        */
852       if (is_add)
853         {
854           dpo_id_t dpo = DPO_INVALID;
855           dpo_proto_t dproto;
856
857           dproto = fib_proto_to_dpo (prefix->fp_proto);
858
859           if (is_drop)
860             ip_null_dpo_add_and_lock (dproto, IP_NULL_ACTION_NONE, &dpo);
861           else if (is_local)
862             receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo);
863           else if (is_unreach)
864             ip_null_dpo_add_and_lock (dproto,
865                                       IP_NULL_ACTION_SEND_ICMP_UNREACH, &dpo);
866           else if (is_prohibit)
867             ip_null_dpo_add_and_lock (dproto,
868                                       IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
869                                       &dpo);
870           else if (is_classify)
871             {
872               if (pool_is_free_index (cm->tables,
873                                       ntohl (classify_table_index)))
874                 {
875                   stats_dsunlock ();
876                   return VNET_API_ERROR_NO_SUCH_TABLE;
877                 }
878
879               dpo_set (&dpo, DPO_CLASSIFY, dproto,
880                        classify_dpo_create (dproto,
881                                             ntohl (classify_table_index)));
882             }
883           else
884             {
885               stats_dsunlock ();
886               return VNET_API_ERROR_NO_SUCH_TABLE;
887             }
888
889           fib_table_entry_special_dpo_update (fib_index,
890                                               prefix,
891                                               FIB_SOURCE_API,
892                                               FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
893           dpo_reset (&dpo);
894         }
895       else
896         {
897           fib_table_entry_special_remove (fib_index, prefix, FIB_SOURCE_API);
898         }
899     }
900   else
901     {
902       if (is_add)
903         {
904           vec_add1 (paths, path);
905           fib_table_entry_update (fib_index,
906                                   prefix, FIB_SOURCE_API, entry_flags, paths);
907           vec_free (paths);
908         }
909       else
910         {
911           fib_table_entry_delete (fib_index, prefix, FIB_SOURCE_API);
912         }
913     }
914
915   stats_dsunlock ();
916   return (0);
917 }
918
919 int
920 add_del_route_check (fib_protocol_t table_proto,
921                      u32 table_id,
922                      u32 next_hop_sw_if_index,
923                      dpo_proto_t next_hop_table_proto,
924                      u32 next_hop_table_id,
925                      u8 is_rpf_id, u32 * fib_index, u32 * next_hop_fib_index)
926 {
927   vnet_main_t *vnm = vnet_get_main ();
928
929   /* Temporaray whilst I do the CSIT dance */
930   u8 create_missing_tables = 1;
931
932   *fib_index = fib_table_find (table_proto, ntohl (table_id));
933   if (~0 == *fib_index)
934     {
935       if (create_missing_tables)
936         {
937           *fib_index = fib_table_find_or_create_and_lock (table_proto,
938                                                           ntohl (table_id),
939                                                           FIB_SOURCE_API);
940         }
941       else
942         {
943           /* No such VRF, and we weren't asked to create one */
944           return VNET_API_ERROR_NO_SUCH_FIB;
945         }
946     }
947
948   if (!is_rpf_id && ~0 != ntohl (next_hop_sw_if_index))
949     {
950       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
951                               ntohl (next_hop_sw_if_index)))
952         {
953           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
954         }
955     }
956   else
957     {
958       fib_protocol_t fib_nh_proto;
959
960       if (next_hop_table_proto > DPO_PROTO_MPLS)
961         return (0);
962
963       fib_nh_proto = dpo_proto_to_fib (next_hop_table_proto);
964
965       if (is_rpf_id)
966         *next_hop_fib_index = mfib_table_find (fib_nh_proto,
967                                                ntohl (next_hop_table_id));
968       else
969         *next_hop_fib_index = fib_table_find (fib_nh_proto,
970                                               ntohl (next_hop_table_id));
971
972       if (~0 == *next_hop_fib_index)
973         {
974           if (create_missing_tables)
975             {
976               if (is_rpf_id)
977                 *next_hop_fib_index =
978                   mfib_table_find_or_create_and_lock (fib_nh_proto,
979                                                       ntohl
980                                                       (next_hop_table_id),
981                                                       MFIB_SOURCE_API);
982               else
983                 *next_hop_fib_index =
984                   fib_table_find_or_create_and_lock (fib_nh_proto,
985                                                      ntohl
986                                                      (next_hop_table_id),
987                                                      FIB_SOURCE_API);
988             }
989           else
990             {
991               /* No such VRF, and we weren't asked to create one */
992               return VNET_API_ERROR_NO_SUCH_FIB;
993             }
994         }
995     }
996
997   return (0);
998 }
999
1000 static int
1001 ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
1002 {
1003   u32 fib_index, next_hop_fib_index;
1004   mpls_label_t *label_stack = NULL;
1005   int rv, ii, n_labels;;
1006
1007   rv = add_del_route_check (FIB_PROTOCOL_IP4,
1008                             mp->table_id,
1009                             mp->next_hop_sw_if_index,
1010                             DPO_PROTO_IP4,
1011                             mp->next_hop_table_id,
1012                             0, &fib_index, &next_hop_fib_index);
1013
1014   if (0 != rv)
1015     return (rv);
1016
1017   fib_prefix_t pfx = {
1018     .fp_len = mp->dst_address_length,
1019     .fp_proto = FIB_PROTOCOL_IP4,
1020   };
1021   clib_memcpy (&pfx.fp_addr.ip4, mp->dst_address, sizeof (pfx.fp_addr.ip4));
1022
1023   ip46_address_t nh;
1024   memset (&nh, 0, sizeof (nh));
1025   memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4));
1026
1027   n_labels = mp->next_hop_n_out_labels;
1028   if (n_labels == 0)
1029     ;
1030   else if (1 == n_labels)
1031     vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
1032   else
1033     {
1034       vec_validate (label_stack, n_labels - 1);
1035       for (ii = 0; ii < n_labels; ii++)
1036         label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
1037     }
1038
1039   return (add_del_route_t_handler (mp->is_multipath,
1040                                    mp->is_add,
1041                                    mp->is_drop,
1042                                    mp->is_unreach,
1043                                    mp->is_prohibit,
1044                                    mp->is_local, 0,
1045                                    mp->is_classify,
1046                                    mp->classify_table_index,
1047                                    mp->is_resolve_host,
1048                                    mp->is_resolve_attached, 0, 0,
1049                                    mp->is_l2_bridged,
1050                                    fib_index, &pfx, DPO_PROTO_IP4,
1051                                    &nh,
1052                                    ntohl (mp->next_hop_sw_if_index),
1053                                    next_hop_fib_index,
1054                                    mp->next_hop_weight,
1055                                    mp->next_hop_preference,
1056                                    ntohl (mp->next_hop_via_label),
1057                                    label_stack));
1058 }
1059
1060 static int
1061 ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
1062 {
1063   u32 fib_index, next_hop_fib_index;
1064   mpls_label_t *label_stack = NULL;
1065   int rv, ii, n_labels;;
1066
1067   rv = add_del_route_check (FIB_PROTOCOL_IP6,
1068                             mp->table_id,
1069                             mp->next_hop_sw_if_index,
1070                             DPO_PROTO_IP6,
1071                             mp->next_hop_table_id,
1072                             0, &fib_index, &next_hop_fib_index);
1073
1074   if (0 != rv)
1075     return (rv);
1076
1077   fib_prefix_t pfx = {
1078     .fp_len = mp->dst_address_length,
1079     .fp_proto = FIB_PROTOCOL_IP6,
1080   };
1081   clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6));
1082
1083   ip46_address_t nh;
1084   memset (&nh, 0, sizeof (nh));
1085   memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6));
1086
1087   n_labels = mp->next_hop_n_out_labels;
1088   if (n_labels == 0)
1089     ;
1090   else if (1 == n_labels)
1091     vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
1092   else
1093     {
1094       vec_validate (label_stack, n_labels - 1);
1095       for (ii = 0; ii < n_labels; ii++)
1096         label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
1097     }
1098
1099   return (add_del_route_t_handler (mp->is_multipath,
1100                                    mp->is_add,
1101                                    mp->is_drop,
1102                                    mp->is_unreach,
1103                                    mp->is_prohibit,
1104                                    mp->is_local, 0,
1105                                    mp->is_classify,
1106                                    mp->classify_table_index,
1107                                    mp->is_resolve_host,
1108                                    mp->is_resolve_attached, 0, 0,
1109                                    mp->is_l2_bridged,
1110                                    fib_index, &pfx, DPO_PROTO_IP6,
1111                                    &nh, ntohl (mp->next_hop_sw_if_index),
1112                                    next_hop_fib_index,
1113                                    mp->next_hop_weight,
1114                                    mp->next_hop_preference,
1115                                    ntohl (mp->next_hop_via_label),
1116                                    label_stack));
1117 }
1118
1119 void
1120 vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
1121 {
1122   vl_api_ip_add_del_route_reply_t *rmp;
1123   int rv;
1124   vnet_main_t *vnm = vnet_get_main ();
1125
1126   vnm->api_errno = 0;
1127
1128   if (mp->is_ipv6)
1129     rv = ip6_add_del_route_t_handler (mp);
1130   else
1131     rv = ip4_add_del_route_t_handler (mp);
1132
1133   rv = (rv == 0) ? vnm->api_errno : rv;
1134
1135   REPLY_MACRO (VL_API_IP_ADD_DEL_ROUTE_REPLY);
1136 }
1137
1138 void
1139 ip_table_create (fib_protocol_t fproto,
1140                  u32 table_id, u8 is_api, const u8 * name)
1141 {
1142   u32 fib_index, mfib_index;
1143
1144   /*
1145    * ignore action on the default table - this is always present
1146    * and cannot be added nor deleted from the API
1147    */
1148   if (0 != table_id)
1149     {
1150       /*
1151        * The API holds only one lock on the table.
1152        * i.e. it can be added many times via the API but needs to be
1153        * deleted only once.
1154        * The FIB index for unicast and multicast is not necessarily the
1155        * same, since internal VPP systesm (like LISP and SR) create
1156        * their own unicast tables.
1157        */
1158       fib_index = fib_table_find (fproto, table_id);
1159       mfib_index = mfib_table_find (fproto, table_id);
1160
1161       if (~0 == fib_index)
1162         {
1163           fib_table_find_or_create_and_lock_w_name (fproto, table_id,
1164                                                     (is_api ?
1165                                                      FIB_SOURCE_API :
1166                                                      FIB_SOURCE_CLI), name);
1167         }
1168       if (~0 == mfib_index)
1169         {
1170           mfib_table_find_or_create_and_lock_w_name (fproto, table_id,
1171                                                      (is_api ?
1172                                                       MFIB_SOURCE_API :
1173                                                       MFIB_SOURCE_CLI), name);
1174         }
1175     }
1176 }
1177
1178 static int
1179 add_del_mroute_check (fib_protocol_t table_proto,
1180                       u32 table_id,
1181                       u32 next_hop_sw_if_index, u8 is_local, u32 * fib_index)
1182 {
1183   vnet_main_t *vnm = vnet_get_main ();
1184
1185   *fib_index = mfib_table_find (table_proto, ntohl (table_id));
1186   if (~0 == *fib_index)
1187     {
1188       /* No such table */
1189       return VNET_API_ERROR_NO_SUCH_FIB;
1190     }
1191
1192   if (~0 != ntohl (next_hop_sw_if_index))
1193     {
1194       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
1195                               ntohl (next_hop_sw_if_index)))
1196         {
1197           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
1198         }
1199     }
1200
1201   return (0);
1202 }
1203
1204 static int
1205 mroute_add_del_handler (u8 is_add,
1206                         u8 is_local,
1207                         u32 fib_index,
1208                         const mfib_prefix_t * prefix,
1209                         u32 entry_flags,
1210                         fib_rpf_id_t rpf_id,
1211                         u32 next_hop_sw_if_index, u32 itf_flags)
1212 {
1213   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
1214
1215   fib_route_path_t path = {
1216     .frp_sw_if_index = next_hop_sw_if_index,
1217     .frp_proto = fib_proto_to_dpo (prefix->fp_proto),
1218   };
1219
1220   if (is_local)
1221     path.frp_flags |= FIB_ROUTE_PATH_LOCAL;
1222
1223
1224   if (!is_local && ~0 == next_hop_sw_if_index)
1225     {
1226       mfib_table_entry_update (fib_index, prefix,
1227                                MFIB_SOURCE_API, rpf_id, entry_flags);
1228     }
1229   else
1230     {
1231       if (is_add)
1232         {
1233           mfib_table_entry_path_update (fib_index, prefix,
1234                                         MFIB_SOURCE_API, &path, itf_flags);
1235         }
1236       else
1237         {
1238           mfib_table_entry_path_remove (fib_index, prefix,
1239                                         MFIB_SOURCE_API, &path);
1240         }
1241     }
1242
1243   stats_dsunlock ();
1244   return (0);
1245 }
1246
1247 static int
1248 api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
1249 {
1250   fib_protocol_t fproto;
1251   u32 fib_index;
1252   int rv;
1253
1254   fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
1255   rv = add_del_mroute_check (fproto,
1256                              mp->table_id,
1257                              mp->next_hop_sw_if_index,
1258                              mp->is_local, &fib_index);
1259
1260   if (0 != rv)
1261     return (rv);
1262
1263   mfib_prefix_t pfx = {
1264     .fp_len = ntohs (mp->grp_address_length),
1265     .fp_proto = fproto,
1266   };
1267
1268   if (FIB_PROTOCOL_IP4 == fproto)
1269     {
1270       clib_memcpy (&pfx.fp_grp_addr.ip4, mp->grp_address,
1271                    sizeof (pfx.fp_grp_addr.ip4));
1272       clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address,
1273                    sizeof (pfx.fp_src_addr.ip4));
1274     }
1275   else
1276     {
1277       clib_memcpy (&pfx.fp_grp_addr.ip6, mp->grp_address,
1278                    sizeof (pfx.fp_grp_addr.ip6));
1279       clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address,
1280                    sizeof (pfx.fp_src_addr.ip6));
1281     }
1282
1283   return (mroute_add_del_handler (mp->is_add,
1284                                   mp->is_local,
1285                                   fib_index, &pfx,
1286                                   ntohl (mp->entry_flags),
1287                                   ntohl (mp->rpf_id),
1288                                   ntohl (mp->next_hop_sw_if_index),
1289                                   ntohl (mp->itf_flags)));
1290 }
1291
1292 void
1293 vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
1294 {
1295   vl_api_ip_mroute_add_del_reply_t *rmp;
1296   int rv;
1297   vnet_main_t *vnm = vnet_get_main ();
1298
1299   vnm->api_errno = 0;
1300
1301   rv = api_mroute_add_del_t_handler (mp);
1302
1303   rv = (rv == 0) ? vnm->api_errno : rv;
1304
1305   REPLY_MACRO (VL_API_IP_MROUTE_ADD_DEL_REPLY);
1306 }
1307
1308 static void
1309 send_ip_details (vpe_api_main_t * am,
1310                  unix_shared_memory_queue_t * q, u32 sw_if_index,
1311                  u8 is_ipv6, u32 context)
1312 {
1313   vl_api_ip_details_t *mp;
1314
1315   mp = vl_msg_api_alloc (sizeof (*mp));
1316   memset (mp, 0, sizeof (*mp));
1317   mp->_vl_msg_id = ntohs (VL_API_IP_DETAILS);
1318
1319   mp->sw_if_index = ntohl (sw_if_index);
1320   mp->is_ipv6 = is_ipv6;
1321   mp->context = context;
1322
1323   vl_msg_api_send_shmem (q, (u8 *) & mp);
1324 }
1325
1326 static void
1327 send_ip_address_details (vpe_api_main_t * am,
1328                          unix_shared_memory_queue_t * q,
1329                          u8 * ip, u16 prefix_length,
1330                          u32 sw_if_index, u8 is_ipv6, u32 context)
1331 {
1332   vl_api_ip_address_details_t *mp;
1333
1334   mp = vl_msg_api_alloc (sizeof (*mp));
1335   memset (mp, 0, sizeof (*mp));
1336   mp->_vl_msg_id = ntohs (VL_API_IP_ADDRESS_DETAILS);
1337
1338   if (is_ipv6)
1339     {
1340       clib_memcpy (&mp->ip, ip, sizeof (mp->ip));
1341     }
1342   else
1343     {
1344       u32 *tp = (u32 *) mp->ip;
1345       *tp = *(u32 *) ip;
1346     }
1347   mp->prefix_length = prefix_length;
1348   mp->context = context;
1349   mp->sw_if_index = htonl (sw_if_index);
1350   mp->is_ipv6 = is_ipv6;
1351
1352   vl_msg_api_send_shmem (q, (u8 *) & mp);
1353 }
1354
1355 static void
1356 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
1357 {
1358   vpe_api_main_t *am = &vpe_api_main;
1359   unix_shared_memory_queue_t *q;
1360   ip6_address_t *r6;
1361   ip4_address_t *r4;
1362   ip6_main_t *im6 = &ip6_main;
1363   ip4_main_t *im4 = &ip4_main;
1364   ip_lookup_main_t *lm6 = &im6->lookup_main;
1365   ip_lookup_main_t *lm4 = &im4->lookup_main;
1366   ip_interface_address_t *ia = 0;
1367   u32 sw_if_index = ~0;
1368   int rv __attribute__ ((unused)) = 0;
1369
1370   VALIDATE_SW_IF_INDEX (mp);
1371
1372   sw_if_index = ntohl (mp->sw_if_index);
1373
1374   q = vl_api_client_index_to_input_queue (mp->client_index);
1375   if (q == 0)
1376     return;
1377
1378   if (mp->is_ipv6)
1379     {
1380       /* *INDENT-OFF* */
1381       foreach_ip_interface_address (lm6, ia, sw_if_index,
1382                                     1 /* honor unnumbered */,
1383       ({
1384         r6 = ip_interface_address_get_address (lm6, ia);
1385         u16 prefix_length = ia->address_length;
1386         send_ip_address_details(am, q, (u8*)r6, prefix_length,
1387                                 sw_if_index, 1, mp->context);
1388       }));
1389       /* *INDENT-ON* */
1390     }
1391   else
1392     {
1393       /* *INDENT-OFF* */
1394       foreach_ip_interface_address (lm4, ia, sw_if_index,
1395                                     1 /* honor unnumbered */,
1396       ({
1397         r4 = ip_interface_address_get_address (lm4, ia);
1398         u16 prefix_length = ia->address_length;
1399         send_ip_address_details(am, q, (u8*)r4, prefix_length,
1400                                 sw_if_index, 0, mp->context);
1401       }));
1402       /* *INDENT-ON* */
1403     }
1404   BAD_SW_IF_INDEX_LABEL;
1405 }
1406
1407 static void
1408 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
1409 {
1410   vpe_api_main_t *am = &vpe_api_main;
1411   vnet_main_t *vnm = vnet_get_main ();
1412   vlib_main_t *vm = vlib_get_main ();
1413   vnet_interface_main_t *im = &vnm->interface_main;
1414   unix_shared_memory_queue_t *q;
1415   vnet_sw_interface_t *si, *sorted_sis;
1416   u32 sw_if_index = ~0;
1417
1418   q = vl_api_client_index_to_input_queue (mp->client_index);
1419   if (q == 0)
1420     {
1421       return;
1422     }
1423
1424   /* Gather interfaces. */
1425   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1426   _vec_len (sorted_sis) = 0;
1427   /* *INDENT-OFF* */
1428   pool_foreach (si, im->sw_interfaces,
1429   ({
1430     vec_add1 (sorted_sis, si[0]);
1431   }));
1432   /* *INDENT-ON* */
1433
1434   vec_foreach (si, sorted_sis)
1435   {
1436     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1437       {
1438         if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index))
1439           {
1440             continue;
1441           }
1442         sw_if_index = si->sw_if_index;
1443         send_ip_details (am, q, sw_if_index, mp->is_ipv6, mp->context);
1444       }
1445   }
1446 }
1447
1448 static void
1449 set_ip6_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1450 {
1451   vl_api_set_ip_flow_hash_reply_t *rmp;
1452   int rv;
1453   u32 table_id;
1454   flow_hash_config_t flow_hash_config = 0;
1455
1456   table_id = ntohl (mp->vrf_id);
1457
1458 #define _(a,b) if (mp->a) flow_hash_config |= b;
1459   foreach_flow_hash_bit;
1460 #undef _
1461
1462   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
1463
1464   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1465 }
1466
1467 static void
1468 set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1469 {
1470   vl_api_set_ip_flow_hash_reply_t *rmp;
1471   int rv;
1472   u32 table_id;
1473   flow_hash_config_t flow_hash_config = 0;
1474
1475   table_id = ntohl (mp->vrf_id);
1476
1477 #define _(a,b) if (mp->a) flow_hash_config |= b;
1478   foreach_flow_hash_bit;
1479 #undef _
1480
1481   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
1482
1483   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1484 }
1485
1486
1487 static void
1488 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t * mp)
1489 {
1490   if (mp->is_ipv6 == 0)
1491     set_ip4_flow_hash (mp);
1492   else
1493     set_ip6_flow_hash (mp);
1494 }
1495
1496 static void
1497   vl_api_sw_interface_ip6nd_ra_config_t_handler
1498   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
1499 {
1500   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
1501   vlib_main_t *vm = vlib_get_main ();
1502   int rv = 0;
1503   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
1504     default_router;
1505
1506   is_no = mp->is_no == 1;
1507   suppress = mp->suppress == 1;
1508   managed = mp->managed == 1;
1509   other = mp->other == 1;
1510   ll_option = mp->ll_option == 1;
1511   send_unicast = mp->send_unicast == 1;
1512   cease = mp->cease == 1;
1513   default_router = mp->default_router == 1;
1514
1515   VALIDATE_SW_IF_INDEX (mp);
1516
1517   rv = ip6_neighbor_ra_config (vm, ntohl (mp->sw_if_index),
1518                                suppress, managed, other,
1519                                ll_option, send_unicast, cease,
1520                                default_router, ntohl (mp->lifetime),
1521                                ntohl (mp->initial_count),
1522                                ntohl (mp->initial_interval),
1523                                ntohl (mp->max_interval),
1524                                ntohl (mp->min_interval), is_no);
1525
1526   BAD_SW_IF_INDEX_LABEL;
1527
1528   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
1529 }
1530
1531 static void
1532   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
1533   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
1534 {
1535   vlib_main_t *vm = vlib_get_main ();
1536   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
1537   int rv = 0;
1538   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
1539
1540   VALIDATE_SW_IF_INDEX (mp);
1541
1542   is_no = mp->is_no == 1;
1543   use_default = mp->use_default == 1;
1544   no_advertise = mp->no_advertise == 1;
1545   off_link = mp->off_link == 1;
1546   no_autoconfig = mp->no_autoconfig == 1;
1547   no_onlink = mp->no_onlink == 1;
1548
1549   rv = ip6_neighbor_ra_prefix (vm, ntohl (mp->sw_if_index),
1550                                (ip6_address_t *) mp->address,
1551                                mp->address_length, use_default,
1552                                ntohl (mp->val_lifetime),
1553                                ntohl (mp->pref_lifetime), no_advertise,
1554                                off_link, no_autoconfig, no_onlink, is_no);
1555
1556   BAD_SW_IF_INDEX_LABEL;
1557   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
1558 }
1559
1560 static void
1561 send_ip6nd_proxy_details (unix_shared_memory_queue_t * q,
1562                           u32 context,
1563                           const ip46_address_t * addr, u32 sw_if_index)
1564 {
1565   vl_api_ip6nd_proxy_details_t *mp;
1566
1567   mp = vl_msg_api_alloc (sizeof (*mp));
1568   memset (mp, 0, sizeof (*mp));
1569   mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
1570   mp->context = context;
1571   mp->sw_if_index = htonl (sw_if_index);
1572   memcpy (mp->address, addr, 16);
1573
1574   vl_msg_api_send_shmem (q, (u8 *) & mp);
1575 }
1576
1577 typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
1578 {
1579   u32 *indices;
1580 } api_ip6nd_proxy_fib_table_walk_ctx_t;
1581
1582 static int
1583 api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
1584 {
1585   api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
1586
1587   if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
1588     {
1589       vec_add1 (ctx->indices, fei);
1590     }
1591
1592   return (1);
1593 }
1594
1595 static void
1596 vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
1597 {
1598   ip6_main_t *im6 = &ip6_main;
1599   fib_table_t *fib_table;
1600   api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
1601     .indices = NULL,
1602   };
1603   fib_node_index_t *feip;
1604   fib_prefix_t pfx;
1605   unix_shared_memory_queue_t *q;
1606
1607   q = vl_api_client_index_to_input_queue (mp->client_index);
1608   if (q == 0)
1609     {
1610       return;
1611     }
1612
1613   /* *INDENT-OFF* */
1614   pool_foreach (fib_table, im6->fibs,
1615   ({
1616     fib_table_walk(fib_table->ft_index,
1617                    FIB_PROTOCOL_IP6,
1618                    api_ip6nd_proxy_fib_table_walk,
1619                    &ctx);
1620   }));
1621   /* *INDENT-ON* */
1622
1623   vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
1624
1625   vec_foreach (feip, ctx.indices)
1626   {
1627     fib_entry_get_prefix (*feip, &pfx);
1628
1629     send_ip6nd_proxy_details (q,
1630                               mp->context,
1631                               &pfx.fp_addr,
1632                               fib_entry_get_resolving_interface (*feip));
1633   }
1634
1635   vec_free (ctx.indices);
1636 }
1637
1638 static void
1639 vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
1640 {
1641   vl_api_ip6nd_proxy_add_del_reply_t *rmp;
1642   int rv = 0;
1643
1644   VALIDATE_SW_IF_INDEX (mp);
1645
1646   rv = ip6_neighbor_proxy_add_del (ntohl (mp->sw_if_index),
1647                                    (ip6_address_t *) mp->address, mp->is_del);
1648
1649   BAD_SW_IF_INDEX_LABEL;
1650   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
1651 }
1652
1653 static void
1654   vl_api_sw_interface_ip6_enable_disable_t_handler
1655   (vl_api_sw_interface_ip6_enable_disable_t * mp)
1656 {
1657   vlib_main_t *vm = vlib_get_main ();
1658   vl_api_sw_interface_ip6_enable_disable_reply_t *rmp;
1659   vnet_main_t *vnm = vnet_get_main ();
1660   int rv = 0;
1661   clib_error_t *error;
1662
1663   vnm->api_errno = 0;
1664
1665   VALIDATE_SW_IF_INDEX (mp);
1666
1667   error =
1668     (mp->enable == 1) ? enable_ip6_interface (vm,
1669                                               ntohl (mp->sw_if_index)) :
1670     disable_ip6_interface (vm, ntohl (mp->sw_if_index));
1671
1672   if (error)
1673     {
1674       clib_error_report (error);
1675       rv = VNET_API_ERROR_UNSPECIFIED;
1676     }
1677   else
1678     {
1679       rv = vnm->api_errno;
1680     }
1681
1682   BAD_SW_IF_INDEX_LABEL;
1683
1684   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
1685 }
1686
1687 static void
1688   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1689   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1690 {
1691   vlib_main_t *vm = vlib_get_main ();
1692   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1693   int rv = 0;
1694   clib_error_t *error;
1695   vnet_main_t *vnm = vnet_get_main ();
1696
1697   vnm->api_errno = 0;
1698
1699   VALIDATE_SW_IF_INDEX (mp);
1700
1701   error = set_ip6_link_local_address (vm,
1702                                       ntohl (mp->sw_if_index),
1703                                       (ip6_address_t *) mp->address);
1704   if (error)
1705     {
1706       clib_error_report (error);
1707       rv = VNET_API_ERROR_UNSPECIFIED;
1708     }
1709   else
1710     {
1711       rv = vnm->api_errno;
1712     }
1713
1714   BAD_SW_IF_INDEX_LABEL;
1715
1716   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1717 }
1718
1719 void
1720 vl_mfib_signal_send_one (unix_shared_memory_queue_t * q,
1721                          u32 context, const mfib_signal_t * mfs)
1722 {
1723   vl_api_mfib_signal_details_t *mp;
1724   mfib_prefix_t prefix;
1725   mfib_table_t *mfib;
1726   mfib_itf_t *mfi;
1727
1728   mp = vl_msg_api_alloc (sizeof (*mp));
1729
1730   memset (mp, 0, sizeof (*mp));
1731   mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS);
1732   mp->context = context;
1733
1734   mfi = mfib_itf_get (mfs->mfs_itf);
1735   mfib_entry_get_prefix (mfs->mfs_entry, &prefix);
1736   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1737                          prefix.fp_proto);
1738   mp->table_id = ntohl (mfib->mft_table_id);
1739   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1740
1741   if (FIB_PROTOCOL_IP4 == prefix.fp_proto)
1742     {
1743       mp->grp_address_len = ntohs (prefix.fp_len);
1744
1745       memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4);
1746       if (prefix.fp_len > 32)
1747         {
1748           memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4);
1749         }
1750     }
1751   else
1752     {
1753       mp->grp_address_len = ntohs (prefix.fp_len);
1754
1755       ASSERT (0);
1756     }
1757
1758   if (0 != mfs->mfs_buffer_len)
1759     {
1760       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1761
1762       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1763     }
1764   else
1765     {
1766       mp->ip_packet_len = 0;
1767     }
1768
1769   vl_msg_api_send_shmem (q, (u8 *) & mp);
1770 }
1771
1772 static void
1773 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1774 {
1775   unix_shared_memory_queue_t *q;
1776
1777   q = vl_api_client_index_to_input_queue (mp->client_index);
1778   if (q == 0)
1779     {
1780       return;
1781     }
1782
1783   while (q->cursize < q->maxsize && mfib_signal_send_one (q, mp->context))
1784     ;
1785 }
1786
1787 #define vl_msg_name_crc_list
1788 #include <vnet/ip/ip.api.h>
1789 #undef vl_msg_name_crc_list
1790
1791 static void
1792 setup_message_id_table (api_main_t * am)
1793 {
1794 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1795   foreach_vl_msg_name_crc_ip;
1796 #undef _
1797 }
1798
1799 static clib_error_t *
1800 ip_api_hookup (vlib_main_t * vm)
1801 {
1802   api_main_t *am = &api_main;
1803
1804 #define _(N,n)                                                  \
1805     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1806                            vl_api_##n##_t_handler,              \
1807                            vl_noop_handler,                     \
1808                            vl_api_##n##_t_endian,               \
1809                            vl_api_##n##_t_print,                \
1810                            sizeof(vl_api_##n##_t), 1);
1811   foreach_ip_api_msg;
1812 #undef _
1813
1814   /*
1815    * Set up the (msg_name, crc, message-id) table
1816    */
1817   setup_message_id_table (am);
1818
1819   return 0;
1820 }
1821
1822 VLIB_API_INIT_FUNCTION (ip_api_hookup);
1823
1824 /*
1825  * fd.io coding-style-patch-verification: ON
1826  *
1827  * Local Variables:
1828  * eval: (c-set-style "gnu")
1829  * End:
1830  */