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