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