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