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