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