Augment IP_DETAILS, IP_ADDRESS_DETAILS with a few context fields.
[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
40 #include <vnet/vnet_msg_enum.h>
41
42 #define vl_typedefs             /* define message structures */
43 #include <vnet/vnet_all_api_h.h>
44 #undef vl_typedefs
45
46 #define vl_endianfun            /* define message structures */
47 #include <vnet/vnet_all_api_h.h>
48 #undef vl_endianfun
49
50 /* instantiate all the print functions we know about */
51 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
52 #define vl_printfun
53 #include <vnet/vnet_all_api_h.h>
54 #undef vl_printfun
55
56 #include <vlibapi/api_helper_macros.h>
57
58 #define foreach_ip_api_msg                                              \
59 _(IP_FIB_DUMP, ip_fib_dump)                                             \
60 _(IP_FIB_DETAILS, ip_fib_details)                                       \
61 _(IP6_FIB_DUMP, ip6_fib_dump)                                           \
62 _(IP6_FIB_DETAILS, ip6_fib_details)                                     \
63 _(IP_NEIGHBOR_DUMP, ip_neighbor_dump)                                   \
64 _(IP_MROUTE_ADD_DEL, ip_mroute_add_del)                                 \
65 _(MFIB_SIGNAL_DUMP, mfib_signal_dump)                                    \
66 _(IP_NEIGHBOR_DETAILS, ip_neighbor_details)                             \
67 _(IP_ADDRESS_DUMP, ip_address_dump)                                     \
68 _(IP_DUMP, ip_dump)                                                     \
69 _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del)                             \
70 _(IP_ADD_DEL_ROUTE, ip_add_del_route)                                   \
71 _(SET_IP_FLOW_HASH,set_ip_flow_hash)                                    \
72 _(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config)           \
73 _(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix)           \
74 _(SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable )    \
75 _(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS,                              \
76   sw_interface_ip6_set_link_local_address)
77
78 extern void stats_dslock_with_hint (int hint, int tag);
79 extern void stats_dsunlock (void);
80
81 static void
82 send_ip_neighbor_details (u8 is_ipv6,
83                           u8 is_static,
84                           u8 * mac_address,
85                           u8 * ip_address,
86                           unix_shared_memory_queue_t * q, u32 context)
87 {
88   vl_api_ip_neighbor_details_t *mp;
89
90   mp = vl_msg_api_alloc (sizeof (*mp));
91   memset (mp, 0, sizeof (*mp));
92   mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS);
93   mp->context = context;
94   mp->is_ipv6 = is_ipv6;
95   mp->is_static = is_static;
96   memcpy (mp->mac_address, mac_address, 6);
97   memcpy (mp->ip_address, ip_address, (is_ipv6) ? 16 : 4);
98
99   vl_msg_api_send_shmem (q, (u8 *) & mp);
100 }
101
102 static void
103 vl_api_ip_neighbor_details_t_handler (vl_api_ip_neighbor_details_t * mp)
104 {
105   clib_warning ("BUG");
106 }
107
108 static void
109 vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
110 {
111   unix_shared_memory_queue_t *q;
112
113   q = vl_api_client_index_to_input_queue (mp->client_index);
114   if (q == 0)
115     return;
116
117   u32 sw_if_index = ntohl (mp->sw_if_index);
118
119   if (mp->is_ipv6)
120     {
121       ip6_neighbor_t *n, *ns;
122
123       ns = ip6_neighbors_entries (sw_if_index);
124       /* *INDENT-OFF* */
125       vec_foreach (n, ns)
126       {
127         send_ip_neighbor_details
128           (mp->is_ipv6, ((n->flags & IP6_NEIGHBOR_FLAG_STATIC) ? 1 : 0),
129            (u8 *) n->link_layer_address,
130            (u8 *) & (n->key.ip6_address.as_u8),
131            q, mp->context);
132       }
133       /* *INDENT-ON* */
134       vec_free (ns);
135     }
136   else
137     {
138       ethernet_arp_ip4_entry_t *n, *ns;
139
140       ns = ip4_neighbor_entries (sw_if_index);
141       /* *INDENT-OFF* */
142       vec_foreach (n, ns)
143       {
144         send_ip_neighbor_details (mp->is_ipv6,
145           ((n->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? 1 : 0),
146           (u8*) n->ethernet_address,
147           (u8*) & (n->ip4_address.as_u8),
148           q, mp->context);
149       }
150       /* *INDENT-ON* */
151       vec_free (ns);
152     }
153 }
154
155
156 void
157 copy_fib_next_hop (fib_route_path_encode_t * api_rpath, void *fp_arg)
158 {
159   int is_ip4;
160   vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg;
161
162   if (api_rpath->rpath.frp_proto == FIB_PROTOCOL_IP4)
163     fp->afi = IP46_TYPE_IP4;
164   else if (api_rpath->rpath.frp_proto == FIB_PROTOCOL_IP6)
165     fp->afi = IP46_TYPE_IP6;
166   else
167     {
168       is_ip4 = ip46_address_is_ip4 (&api_rpath->rpath.frp_addr);
169       if (is_ip4)
170         fp->afi = IP46_TYPE_IP4;
171       else
172         fp->afi = IP46_TYPE_IP6;
173     }
174   if (fp->afi == IP46_TYPE_IP4)
175     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip4,
176             sizeof (api_rpath->rpath.frp_addr.ip4));
177   else
178     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip6,
179             sizeof (api_rpath->rpath.frp_addr.ip6));
180 }
181
182 static void
183 vl_api_ip_fib_details_t_handler (vl_api_ip_fib_details_t * mp)
184 {
185   clib_warning ("BUG");
186 }
187
188 static void
189 vl_api_ip_fib_details_t_endian (vl_api_ip_fib_details_t * mp)
190 {
191   clib_warning ("BUG");
192 }
193
194 static void
195 vl_api_ip_fib_details_t_print (vl_api_ip_fib_details_t * mp)
196 {
197   clib_warning ("BUG");
198 }
199
200 static void
201 send_ip_fib_details (vpe_api_main_t * am,
202                      unix_shared_memory_queue_t * q,
203                      u32 table_id, fib_prefix_t * pfx,
204                      fib_route_path_encode_t * api_rpaths, u32 context)
205 {
206   vl_api_ip_fib_details_t *mp;
207   fib_route_path_encode_t *api_rpath;
208   vl_api_fib_path_t *fp;
209   int path_count;
210
211   path_count = vec_len (api_rpaths);
212   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
213   if (!mp)
214     return;
215   memset (mp, 0, sizeof (*mp));
216   mp->_vl_msg_id = ntohs (VL_API_IP_FIB_DETAILS);
217   mp->context = context;
218
219   mp->table_id = htonl (table_id);
220   mp->address_length = pfx->fp_len;
221   memcpy (mp->address, &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
222
223   mp->count = htonl (path_count);
224   fp = mp->path;
225   vec_foreach (api_rpath, api_rpaths)
226   {
227     memset (fp, 0, sizeof (*fp));
228     switch (api_rpath->dpo.dpoi_type)
229       {
230       case DPO_RECEIVE:
231         fp->is_local = true;
232         break;
233       case DPO_DROP:
234         fp->is_drop = true;
235         break;
236       case DPO_IP_NULL:
237         switch (api_rpath->dpo.dpoi_index)
238           {
239           case IP_NULL_ACTION_NONE:
240             fp->is_drop = true;
241             break;
242           case IP_NULL_ACTION_SEND_ICMP_UNREACH:
243             fp->is_unreach = true;
244             break;
245           case IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
246             fp->is_prohibit = true;
247             break;
248           default:
249             break;
250           }
251         break;
252       default:
253         break;
254       }
255     fp->weight = htonl (api_rpath->rpath.frp_weight);
256     fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
257     copy_fib_next_hop (api_rpath, fp);
258     fp++;
259   }
260
261   vl_msg_api_send_shmem (q, (u8 *) & mp);
262 }
263
264 static void
265 vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp)
266 {
267   vpe_api_main_t *am = &vpe_api_main;
268   unix_shared_memory_queue_t *q;
269   ip4_main_t *im = &ip4_main;
270   fib_table_t *fib_table;
271   fib_node_index_t lfei, *lfeip, *lfeis = NULL;
272   mpls_label_t key;
273   fib_prefix_t pfx;
274   u32 fib_index;
275   fib_route_path_encode_t *api_rpaths;
276   int i;
277
278   q = vl_api_client_index_to_input_queue (mp->client_index);
279   if (q == 0)
280     return;
281
282   /* *INDENT-OFF* */
283   pool_foreach (fib_table, im->fibs,
284   ({
285     for (i = 0; i < ARRAY_LEN (fib_table->v4.fib_entry_by_dst_address); i++)
286       {
287         hash_foreach(key, lfei, fib_table->v4.fib_entry_by_dst_address[i],
288         ({
289           vec_add1(lfeis, lfei);
290         }));
291       }
292   }));
293   /* *INDENT-ON* */
294
295   vec_sort_with_function (lfeis, fib_entry_cmp_for_sort);
296
297   vec_foreach (lfeip, lfeis)
298   {
299     fib_entry_get_prefix (*lfeip, &pfx);
300     fib_index = fib_entry_get_fib_index (*lfeip);
301     fib_table = fib_table_get (fib_index, pfx.fp_proto);
302     api_rpaths = NULL;
303     fib_entry_encode (*lfeip, &api_rpaths);
304     send_ip_fib_details (am, q,
305                          fib_table->ft_table_id, &pfx, api_rpaths,
306                          mp->context);
307     vec_free (api_rpaths);
308   }
309
310   vec_free (lfeis);
311 }
312
313 static void
314 vl_api_ip6_fib_details_t_handler (vl_api_ip6_fib_details_t * mp)
315 {
316   clib_warning ("BUG");
317 }
318
319 static void
320 vl_api_ip6_fib_details_t_endian (vl_api_ip6_fib_details_t * mp)
321 {
322   clib_warning ("BUG");
323 }
324
325 static void
326 vl_api_ip6_fib_details_t_print (vl_api_ip6_fib_details_t * mp)
327 {
328   clib_warning ("BUG");
329 }
330
331 static void
332 send_ip6_fib_details (vpe_api_main_t * am,
333                       unix_shared_memory_queue_t * q,
334                       u32 table_id, fib_prefix_t * pfx,
335                       fib_route_path_encode_t * api_rpaths, u32 context)
336 {
337   vl_api_ip6_fib_details_t *mp;
338   fib_route_path_encode_t *api_rpath;
339   vl_api_fib_path_t *fp;
340   int path_count;
341
342   path_count = vec_len (api_rpaths);
343   mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
344   if (!mp)
345     return;
346   memset (mp, 0, sizeof (*mp));
347   mp->_vl_msg_id = ntohs (VL_API_IP6_FIB_DETAILS);
348   mp->context = context;
349
350   mp->table_id = htonl (table_id);
351   mp->address_length = pfx->fp_len;
352   memcpy (mp->address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
353
354   mp->count = htonl (path_count);
355   fp = mp->path;
356   vec_foreach (api_rpath, api_rpaths)
357   {
358     memset (fp, 0, sizeof (*fp));
359     switch (api_rpath->dpo.dpoi_type)
360       {
361       case DPO_RECEIVE:
362         fp->is_local = true;
363         break;
364       case DPO_DROP:
365         fp->is_drop = true;
366         break;
367       case DPO_IP_NULL:
368         switch (api_rpath->dpo.dpoi_index)
369           {
370           case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_NONE:
371             fp->is_drop = true;
372             break;
373           case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_SEND_ICMP_UNREACH:
374             fp->is_unreach = true;
375             break;
376           case IP_NULL_DPO_ACTION_NUM + IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
377             fp->is_prohibit = true;
378             break;
379           default:
380             break;
381           }
382         break;
383       default:
384         break;
385       }
386     fp->weight = htonl (api_rpath->rpath.frp_weight);
387     fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
388     copy_fib_next_hop (api_rpath, fp);
389     fp++;
390   }
391
392   vl_msg_api_send_shmem (q, (u8 *) & mp);
393 }
394
395 typedef struct apt_ip6_fib_show_ctx_t_
396 {
397   u32 fib_index;
398   fib_node_index_t *entries;
399 } api_ip6_fib_show_ctx_t;
400
401 static void
402 api_ip6_fib_table_put_entries (clib_bihash_kv_24_8_t * kvp, void *arg)
403 {
404   api_ip6_fib_show_ctx_t *ctx = arg;
405
406   if ((kvp->key[2] >> 32) == ctx->fib_index)
407     {
408       vec_add1 (ctx->entries, kvp->value);
409     }
410 }
411
412 static void
413 api_ip6_fib_table_get_all (unix_shared_memory_queue_t * q,
414                            vl_api_ip6_fib_dump_t * mp,
415                            fib_table_t * fib_table)
416 {
417   vpe_api_main_t *am = &vpe_api_main;
418   ip6_main_t *im6 = &ip6_main;
419   ip6_fib_t *fib = &fib_table->v6;
420   fib_node_index_t *fib_entry_index;
421   api_ip6_fib_show_ctx_t ctx = {
422     .fib_index = fib->index,.entries = NULL,
423   };
424   fib_route_path_encode_t *api_rpaths;
425   fib_prefix_t pfx;
426
427   BV (clib_bihash_foreach_key_value_pair)
428     ((BVT (clib_bihash) *) & im6->ip6_table[IP6_FIB_TABLE_NON_FWDING].
429      ip6_hash, api_ip6_fib_table_put_entries, &ctx);
430
431   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
432
433   vec_foreach (fib_entry_index, ctx.entries)
434   {
435     fib_entry_get_prefix (*fib_entry_index, &pfx);
436     api_rpaths = NULL;
437     fib_entry_encode (*fib_entry_index, &api_rpaths);
438     send_ip6_fib_details (am, q,
439                           fib_table->ft_table_id,
440                           &pfx, api_rpaths, mp->context);
441     vec_free (api_rpaths);
442   }
443
444   vec_free (ctx.entries);
445 }
446
447 static void
448 vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp)
449 {
450   unix_shared_memory_queue_t *q;
451   ip6_main_t *im6 = &ip6_main;
452   fib_table_t *fib_table;
453
454   q = vl_api_client_index_to_input_queue (mp->client_index);
455   if (q == 0)
456     return;
457
458   /* *INDENT-OFF* */
459   pool_foreach (fib_table, im6->fibs,
460   ({
461     api_ip6_fib_table_get_all(q, mp, fib_table);
462   }));
463   /* *INDENT-ON* */
464 }
465
466 static void
467 vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
468                                       vlib_main_t * vm)
469 {
470   vl_api_ip_neighbor_add_del_reply_t *rmp;
471   vnet_main_t *vnm = vnet_get_main ();
472   int rv = 0;
473
474   VALIDATE_SW_IF_INDEX (mp);
475
476   stats_dslock_with_hint (1 /* release hint */ , 7 /* tag */ );
477
478   /*
479    * there's no validation here of the ND/ARP entry being added.
480    * The expectation is that the FIB will ensure that nothing bad
481    * will come of adding bogus entries.
482    */
483   if (mp->is_ipv6)
484     {
485       if (mp->is_add)
486         rv = vnet_set_ip6_ethernet_neighbor
487           (vm, ntohl (mp->sw_if_index),
488            (ip6_address_t *) (mp->dst_address),
489            mp->mac_address, sizeof (mp->mac_address), mp->is_static);
490       else
491         rv = vnet_unset_ip6_ethernet_neighbor
492           (vm, ntohl (mp->sw_if_index),
493            (ip6_address_t *) (mp->dst_address),
494            mp->mac_address, sizeof (mp->mac_address));
495     }
496   else
497     {
498       ethernet_arp_ip4_over_ethernet_address_t a;
499
500       clib_memcpy (&a.ethernet, mp->mac_address, 6);
501       clib_memcpy (&a.ip4, mp->dst_address, 4);
502
503       if (mp->is_add)
504         rv = vnet_arp_set_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index),
505                                              &a, mp->is_static);
506       else
507         rv =
508           vnet_arp_unset_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index), &a);
509     }
510
511   BAD_SW_IF_INDEX_LABEL;
512
513   stats_dsunlock ();
514   REPLY_MACRO (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY);
515 }
516
517 int
518 add_del_route_t_handler (u8 is_multipath,
519                          u8 is_add,
520                          u8 is_drop,
521                          u8 is_unreach,
522                          u8 is_prohibit,
523                          u8 is_local,
524                          u8 is_classify,
525                          u32 classify_table_index,
526                          u8 is_resolve_host,
527                          u8 is_resolve_attached,
528                          u32 fib_index,
529                          const fib_prefix_t * prefix,
530                          u8 next_hop_proto_is_ip4,
531                          const ip46_address_t * next_hop,
532                          u32 next_hop_sw_if_index,
533                          u8 next_hop_fib_index,
534                          u32 next_hop_weight,
535                          mpls_label_t next_hop_via_label,
536                          mpls_label_t * next_hop_out_label_stack)
537 {
538   vnet_classify_main_t *cm = &vnet_classify_main;
539   fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE;
540   fib_route_path_t path = {
541     .frp_proto = (next_hop_proto_is_ip4 ?
542                   FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6),
543     .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
544     .frp_sw_if_index = next_hop_sw_if_index,
545     .frp_fib_index = next_hop_fib_index,
546     .frp_weight = next_hop_weight,
547     .frp_label_stack = next_hop_out_label_stack,
548   };
549   fib_route_path_t *paths = NULL;
550
551   if (MPLS_LABEL_INVALID != next_hop_via_label)
552     {
553       path.frp_proto = FIB_PROTOCOL_MPLS;
554       path.frp_local_label = next_hop_via_label;
555     }
556   if (is_resolve_host)
557     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
558   if (is_resolve_attached)
559     path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
560
561   path.frp_flags = path_flags;
562
563   if (is_multipath)
564     {
565       stats_dslock_with_hint (1 /* release hint */ , 10 /* tag */ );
566
567
568       vec_add1 (paths, path);
569
570       if (is_add)
571         fib_table_entry_path_add2 (fib_index,
572                                    prefix,
573                                    FIB_SOURCE_API,
574                                    FIB_ENTRY_FLAG_NONE, paths);
575       else
576         fib_table_entry_path_remove2 (fib_index,
577                                       prefix, FIB_SOURCE_API, paths);
578
579       vec_free (paths);
580       stats_dsunlock ();
581       return 0;
582     }
583
584   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
585
586   if (is_drop || is_local || is_classify || is_unreach || is_prohibit)
587     {
588       /*
589        * special route types that link directly to the adj
590        */
591       if (is_add)
592         {
593           dpo_id_t dpo = DPO_INVALID;
594           dpo_proto_t dproto;
595
596           dproto = fib_proto_to_dpo (prefix->fp_proto);
597
598           if (is_drop)
599             ip_null_dpo_add_and_lock (dproto, IP_NULL_ACTION_NONE, &dpo);
600           else if (is_local)
601             receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo);
602           else if (is_unreach)
603             ip_null_dpo_add_and_lock (dproto,
604                                       IP_NULL_ACTION_SEND_ICMP_UNREACH, &dpo);
605           else if (is_prohibit)
606             ip_null_dpo_add_and_lock (dproto,
607                                       IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
608                                       &dpo);
609           else if (is_classify)
610             {
611               if (pool_is_free_index (cm->tables,
612                                       ntohl (classify_table_index)))
613                 {
614                   stats_dsunlock ();
615                   return VNET_API_ERROR_NO_SUCH_TABLE;
616                 }
617
618               dpo_set (&dpo, DPO_CLASSIFY, dproto,
619                        classify_dpo_create (dproto,
620                                             ntohl (classify_table_index)));
621             }
622           else
623             {
624               stats_dsunlock ();
625               return VNET_API_ERROR_NO_SUCH_TABLE;
626             }
627
628           fib_table_entry_special_dpo_update (fib_index,
629                                               prefix,
630                                               FIB_SOURCE_API,
631                                               FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
632           dpo_reset (&dpo);
633         }
634       else
635         {
636           fib_table_entry_special_remove (fib_index, prefix, FIB_SOURCE_API);
637         }
638     }
639   else
640     {
641       if (is_add)
642         {
643           vec_add1 (paths, path);
644           fib_table_entry_update (fib_index,
645                                   prefix,
646                                   FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, paths);
647           vec_free (paths);
648         }
649       else
650         {
651           fib_table_entry_delete (fib_index, prefix, FIB_SOURCE_API);
652         }
653     }
654
655   stats_dsunlock ();
656   return (0);
657 }
658
659 int
660 add_del_route_check (fib_protocol_t table_proto,
661                      u32 table_id,
662                      u32 next_hop_sw_if_index,
663                      fib_protocol_t next_hop_table_proto,
664                      u32 next_hop_table_id,
665                      u8 create_missing_tables,
666                      u32 * fib_index, u32 * next_hop_fib_index)
667 {
668   vnet_main_t *vnm = vnet_get_main ();
669
670   *fib_index = fib_table_find (table_proto, ntohl (table_id));
671   if (~0 == *fib_index)
672     {
673       if (create_missing_tables)
674         {
675           *fib_index = fib_table_find_or_create_and_lock (table_proto,
676                                                           ntohl (table_id));
677         }
678       else
679         {
680           /* No such VRF, and we weren't asked to create one */
681           return VNET_API_ERROR_NO_SUCH_FIB;
682         }
683     }
684
685   if (~0 != ntohl (next_hop_sw_if_index))
686     {
687       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
688                               ntohl (next_hop_sw_if_index)))
689         {
690           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
691         }
692     }
693   else
694     {
695       *next_hop_fib_index = fib_table_find (next_hop_table_proto,
696                                             ntohl (next_hop_table_id));
697
698       if (~0 == *next_hop_fib_index)
699         {
700           if (create_missing_tables)
701             {
702               *next_hop_fib_index =
703                 fib_table_find_or_create_and_lock (next_hop_table_proto,
704                                                    ntohl (next_hop_table_id));
705             }
706           else
707             {
708               /* No such VRF, and we weren't asked to create one */
709               return VNET_API_ERROR_NO_SUCH_FIB;
710             }
711         }
712     }
713
714   return (0);
715 }
716
717 static int
718 ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
719 {
720   u32 fib_index, next_hop_fib_index;
721   mpls_label_t *label_stack = NULL;
722   int rv, ii, n_labels;;
723
724   rv = add_del_route_check (FIB_PROTOCOL_IP4,
725                             mp->table_id,
726                             mp->next_hop_sw_if_index,
727                             FIB_PROTOCOL_IP4,
728                             mp->next_hop_table_id,
729                             mp->create_vrf_if_needed,
730                             &fib_index, &next_hop_fib_index);
731
732   if (0 != rv)
733     return (rv);
734
735   fib_prefix_t pfx = {
736     .fp_len = mp->dst_address_length,
737     .fp_proto = FIB_PROTOCOL_IP4,
738   };
739   clib_memcpy (&pfx.fp_addr.ip4, mp->dst_address, sizeof (pfx.fp_addr.ip4));
740
741   ip46_address_t nh;
742   memset (&nh, 0, sizeof (nh));
743   memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4));
744
745   n_labels = mp->next_hop_n_out_labels;
746   if (n_labels == 0)
747     ;
748   else if (1 == n_labels)
749     vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
750   else
751     {
752       vec_validate (label_stack, n_labels - 1);
753       for (ii = 0; ii < n_labels; ii++)
754         label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
755     }
756
757   return (add_del_route_t_handler (mp->is_multipath,
758                                    mp->is_add,
759                                    mp->is_drop,
760                                    mp->is_unreach,
761                                    mp->is_prohibit,
762                                    mp->is_local,
763                                    mp->is_classify,
764                                    mp->classify_table_index,
765                                    mp->is_resolve_host,
766                                    mp->is_resolve_attached,
767                                    fib_index, &pfx, 1,
768                                    &nh,
769                                    ntohl (mp->next_hop_sw_if_index),
770                                    next_hop_fib_index,
771                                    mp->next_hop_weight,
772                                    ntohl (mp->next_hop_via_label),
773                                    label_stack));
774 }
775
776 static int
777 ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
778 {
779   u32 fib_index, next_hop_fib_index;
780   mpls_label_t *label_stack = NULL;
781   int rv, ii, n_labels;;
782
783   rv = add_del_route_check (FIB_PROTOCOL_IP6,
784                             mp->table_id,
785                             mp->next_hop_sw_if_index,
786                             FIB_PROTOCOL_IP6,
787                             mp->next_hop_table_id,
788                             mp->create_vrf_if_needed,
789                             &fib_index, &next_hop_fib_index);
790
791   if (0 != rv)
792     return (rv);
793
794   fib_prefix_t pfx = {
795     .fp_len = mp->dst_address_length,
796     .fp_proto = FIB_PROTOCOL_IP6,
797   };
798   clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6));
799
800   ip46_address_t nh;
801   memset (&nh, 0, sizeof (nh));
802   memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6));
803
804   n_labels = mp->next_hop_n_out_labels;
805   if (n_labels == 0)
806     ;
807   else if (1 == n_labels)
808     vec_add1 (label_stack, ntohl (mp->next_hop_out_label_stack[0]));
809   else
810     {
811       vec_validate (label_stack, n_labels - 1);
812       for (ii = 0; ii < n_labels; ii++)
813         label_stack[ii] = ntohl (mp->next_hop_out_label_stack[ii]);
814     }
815
816   return (add_del_route_t_handler (mp->is_multipath,
817                                    mp->is_add,
818                                    mp->is_drop,
819                                    mp->is_unreach,
820                                    mp->is_prohibit,
821                                    mp->is_local,
822                                    mp->is_classify,
823                                    mp->classify_table_index,
824                                    mp->is_resolve_host,
825                                    mp->is_resolve_attached,
826                                    fib_index, &pfx, 0,
827                                    &nh, ntohl (mp->next_hop_sw_if_index),
828                                    next_hop_fib_index,
829                                    mp->next_hop_weight,
830                                    ntohl (mp->next_hop_via_label),
831                                    label_stack));
832 }
833
834 void
835 vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
836 {
837   vl_api_ip_add_del_route_reply_t *rmp;
838   int rv;
839   vnet_main_t *vnm = vnet_get_main ();
840
841   vnm->api_errno = 0;
842
843   if (mp->is_ipv6)
844     rv = ip6_add_del_route_t_handler (mp);
845   else
846     rv = ip4_add_del_route_t_handler (mp);
847
848   rv = (rv == 0) ? vnm->api_errno : rv;
849
850   REPLY_MACRO (VL_API_IP_ADD_DEL_ROUTE_REPLY);
851 }
852
853 static int
854 add_del_mroute_check (fib_protocol_t table_proto,
855                       u32 table_id,
856                       u32 next_hop_sw_if_index,
857                       u8 is_local, u8 create_missing_tables, u32 * fib_index)
858 {
859   vnet_main_t *vnm = vnet_get_main ();
860
861   *fib_index = mfib_table_find (table_proto, ntohl (table_id));
862   if (~0 == *fib_index)
863     {
864       if (create_missing_tables)
865         {
866           *fib_index = mfib_table_find_or_create_and_lock (table_proto,
867                                                            ntohl (table_id));
868         }
869       else
870         {
871           /* No such VRF, and we weren't asked to create one */
872           return VNET_API_ERROR_NO_SUCH_FIB;
873         }
874     }
875
876   if (~0 != ntohl (next_hop_sw_if_index))
877     {
878       if (pool_is_free_index (vnm->interface_main.sw_interfaces,
879                               ntohl (next_hop_sw_if_index)))
880         {
881           return VNET_API_ERROR_NO_MATCHING_INTERFACE;
882         }
883     }
884
885   return (0);
886 }
887
888 static int
889 mroute_add_del_handler (u8 is_add,
890                         u8 is_local,
891                         u32 fib_index,
892                         const mfib_prefix_t * prefix,
893                         u32 entry_flags,
894                         u32 next_hop_sw_if_index, u32 itf_flags)
895 {
896   stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
897
898   fib_route_path_t path = {
899     .frp_sw_if_index = next_hop_sw_if_index,
900     .frp_proto = prefix->fp_proto,
901   };
902
903   if (is_local)
904     path.frp_flags |= FIB_ROUTE_PATH_LOCAL;
905
906
907   if (!is_local && ~0 == next_hop_sw_if_index)
908     {
909       mfib_table_entry_update (fib_index, prefix,
910                                MFIB_SOURCE_API, entry_flags);
911     }
912   else
913     {
914       if (is_add)
915         {
916           mfib_table_entry_path_update (fib_index, prefix,
917                                         MFIB_SOURCE_API, &path, itf_flags);
918         }
919       else
920         {
921           mfib_table_entry_path_remove (fib_index, prefix,
922                                         MFIB_SOURCE_API, &path);
923         }
924     }
925
926   stats_dsunlock ();
927   return (0);
928 }
929
930 static int
931 api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
932 {
933   fib_protocol_t fproto;
934   u32 fib_index;
935   int rv;
936
937   fproto = (mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
938   rv = add_del_mroute_check (fproto,
939                              mp->table_id,
940                              mp->next_hop_sw_if_index,
941                              mp->is_local,
942                              mp->create_vrf_if_needed, &fib_index);
943
944   if (0 != rv)
945     return (rv);
946
947   mfib_prefix_t pfx = {
948     .fp_len = ntohs (mp->grp_address_length),
949     .fp_proto = fproto,
950   };
951
952   if (FIB_PROTOCOL_IP4 == fproto)
953     {
954       clib_memcpy (&pfx.fp_grp_addr.ip4, mp->grp_address,
955                    sizeof (pfx.fp_grp_addr.ip4));
956       clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address,
957                    sizeof (pfx.fp_src_addr.ip4));
958     }
959   else
960     {
961       clib_memcpy (&pfx.fp_grp_addr.ip6, mp->grp_address,
962                    sizeof (pfx.fp_grp_addr.ip6));
963       clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address,
964                    sizeof (pfx.fp_src_addr.ip6));
965     }
966
967   return (mroute_add_del_handler (mp->is_add,
968                                   mp->is_local,
969                                   fib_index, &pfx,
970                                   ntohl (mp->entry_flags),
971                                   ntohl (mp->next_hop_sw_if_index),
972                                   ntohl (mp->itf_flags)));
973 }
974
975 void
976 vl_api_ip_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
977 {
978   vl_api_ip_mroute_add_del_reply_t *rmp;
979   int rv;
980   vnet_main_t *vnm = vnet_get_main ();
981
982   vnm->api_errno = 0;
983
984   rv = api_mroute_add_del_t_handler (mp);
985
986   rv = (rv == 0) ? vnm->api_errno : rv;
987
988   REPLY_MACRO (VL_API_IP_MROUTE_ADD_DEL_REPLY);
989 }
990
991 static void
992 send_ip_details (vpe_api_main_t * am,
993                  unix_shared_memory_queue_t * q, u32 sw_if_index,
994                  u8 is_ipv6, u32 context)
995 {
996   vl_api_ip_details_t *mp;
997
998   mp = vl_msg_api_alloc (sizeof (*mp));
999   memset (mp, 0, sizeof (*mp));
1000   mp->_vl_msg_id = ntohs (VL_API_IP_DETAILS);
1001
1002   mp->sw_if_index = ntohl (sw_if_index);
1003   mp->is_ipv6 = is_ipv6;
1004   mp->context = context;
1005
1006   vl_msg_api_send_shmem (q, (u8 *) & mp);
1007 }
1008
1009 static void
1010 send_ip_address_details (vpe_api_main_t * am,
1011                          unix_shared_memory_queue_t * q,
1012                          u8 * ip, u16 prefix_length,
1013                          u32 sw_if_index, u8 is_ipv6, u32 context)
1014 {
1015   vl_api_ip_address_details_t *mp;
1016
1017   mp = vl_msg_api_alloc (sizeof (*mp));
1018   memset (mp, 0, sizeof (*mp));
1019   mp->_vl_msg_id = ntohs (VL_API_IP_ADDRESS_DETAILS);
1020
1021   if (is_ipv6)
1022     {
1023       clib_memcpy (&mp->ip, ip, sizeof (mp->ip));
1024     }
1025   else
1026     {
1027       u32 *tp = (u32 *) mp->ip;
1028       *tp = *(u32 *) ip;
1029     }
1030   mp->prefix_length = prefix_length;
1031   mp->context = context;
1032   mp->sw_if_index = htonl (sw_if_index);
1033   mp->is_ipv6 = is_ipv6;
1034
1035   vl_msg_api_send_shmem (q, (u8 *) & mp);
1036 }
1037
1038 static void
1039 vl_api_ip_address_dump_t_handler (vl_api_ip_address_dump_t * mp)
1040 {
1041   vpe_api_main_t *am = &vpe_api_main;
1042   unix_shared_memory_queue_t *q;
1043   ip6_address_t *r6;
1044   ip4_address_t *r4;
1045   ip6_main_t *im6 = &ip6_main;
1046   ip4_main_t *im4 = &ip4_main;
1047   ip_lookup_main_t *lm6 = &im6->lookup_main;
1048   ip_lookup_main_t *lm4 = &im4->lookup_main;
1049   ip_interface_address_t *ia = 0;
1050   u32 sw_if_index = ~0;
1051   int rv __attribute__ ((unused)) = 0;
1052
1053   VALIDATE_SW_IF_INDEX (mp);
1054
1055   sw_if_index = ntohl (mp->sw_if_index);
1056
1057   q = vl_api_client_index_to_input_queue (mp->client_index);
1058   if (q == 0)
1059     return;
1060
1061   if (mp->is_ipv6)
1062     {
1063       /* *INDENT-OFF* */
1064       foreach_ip_interface_address (lm6, ia, sw_if_index,
1065                                     1 /* honor unnumbered */,
1066       ({
1067         r6 = ip_interface_address_get_address (lm6, ia);
1068         u16 prefix_length = ia->address_length;
1069         send_ip_address_details(am, q, (u8*)r6, prefix_length,
1070                                 sw_if_index, 1, mp->context);
1071       }));
1072       /* *INDENT-ON* */
1073     }
1074   else
1075     {
1076       /* *INDENT-OFF* */
1077       foreach_ip_interface_address (lm4, ia, sw_if_index,
1078                                     1 /* honor unnumbered */,
1079       ({
1080         r4 = ip_interface_address_get_address (lm4, ia);
1081         u16 prefix_length = ia->address_length;
1082         send_ip_address_details(am, q, (u8*)r4, prefix_length,
1083                                 sw_if_index, 0, mp->context);
1084       }));
1085       /* *INDENT-ON* */
1086     }
1087   BAD_SW_IF_INDEX_LABEL;
1088 }
1089
1090 static void
1091 vl_api_ip_dump_t_handler (vl_api_ip_dump_t * mp)
1092 {
1093   vpe_api_main_t *am = &vpe_api_main;
1094   vnet_main_t *vnm = vnet_get_main ();
1095   vlib_main_t *vm = vlib_get_main ();
1096   vnet_interface_main_t *im = &vnm->interface_main;
1097   unix_shared_memory_queue_t *q;
1098   vnet_sw_interface_t *si, *sorted_sis;
1099   u32 sw_if_index = ~0;
1100
1101   q = vl_api_client_index_to_input_queue (mp->client_index);
1102   if (q == 0)
1103     {
1104       return;
1105     }
1106
1107   /* Gather interfaces. */
1108   sorted_sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1109   _vec_len (sorted_sis) = 0;
1110   /* *INDENT-OFF* */
1111   pool_foreach (si, im->sw_interfaces,
1112   ({
1113     vec_add1 (sorted_sis, si[0]);
1114   }));
1115   /* *INDENT-ON* */
1116
1117   vec_foreach (si, sorted_sis)
1118   {
1119     if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1120       {
1121         if (mp->is_ipv6 && !ip6_interface_enabled (vm, si->sw_if_index))
1122           {
1123             continue;
1124           }
1125         sw_if_index = si->sw_if_index;
1126         send_ip_details (am, q, sw_if_index, mp->is_ipv6, mp->context);
1127       }
1128   }
1129 }
1130
1131 static void
1132 set_ip6_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1133 {
1134   vl_api_set_ip_flow_hash_reply_t *rmp;
1135   int rv = VNET_API_ERROR_UNIMPLEMENTED;
1136
1137   clib_warning ("unimplemented...");
1138
1139   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1140 }
1141
1142 static void
1143 set_ip4_flow_hash (vl_api_set_ip_flow_hash_t * mp)
1144 {
1145   vl_api_set_ip_flow_hash_reply_t *rmp;
1146   int rv;
1147   u32 table_id;
1148   flow_hash_config_t flow_hash_config = 0;
1149
1150   table_id = ntohl (mp->vrf_id);
1151
1152 #define _(a,b) if (mp->a) flow_hash_config |= b;
1153   foreach_flow_hash_bit;
1154 #undef _
1155
1156   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
1157
1158   REPLY_MACRO (VL_API_SET_IP_FLOW_HASH_REPLY);
1159 }
1160
1161
1162 static void
1163 vl_api_set_ip_flow_hash_t_handler (vl_api_set_ip_flow_hash_t * mp)
1164 {
1165   if (mp->is_ipv6 == 0)
1166     set_ip4_flow_hash (mp);
1167   else
1168     set_ip6_flow_hash (mp);
1169 }
1170
1171 static void
1172   vl_api_sw_interface_ip6nd_ra_config_t_handler
1173   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
1174 {
1175   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
1176   vlib_main_t *vm = vlib_get_main ();
1177   int rv = 0;
1178   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
1179     default_router;
1180
1181   is_no = mp->is_no == 1;
1182   suppress = mp->suppress == 1;
1183   managed = mp->managed == 1;
1184   other = mp->other == 1;
1185   ll_option = mp->ll_option == 1;
1186   send_unicast = mp->send_unicast == 1;
1187   cease = mp->cease == 1;
1188   default_router = mp->default_router == 1;
1189
1190   VALIDATE_SW_IF_INDEX (mp);
1191
1192   rv = ip6_neighbor_ra_config (vm, ntohl (mp->sw_if_index),
1193                                suppress, managed, other,
1194                                ll_option, send_unicast, cease,
1195                                default_router, ntohl (mp->lifetime),
1196                                ntohl (mp->initial_count),
1197                                ntohl (mp->initial_interval),
1198                                ntohl (mp->max_interval),
1199                                ntohl (mp->min_interval), is_no);
1200
1201   BAD_SW_IF_INDEX_LABEL;
1202
1203   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
1204 }
1205
1206 static void
1207   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
1208   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
1209 {
1210   vlib_main_t *vm = vlib_get_main ();
1211   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
1212   int rv = 0;
1213   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
1214
1215   VALIDATE_SW_IF_INDEX (mp);
1216
1217   is_no = mp->is_no == 1;
1218   use_default = mp->use_default == 1;
1219   no_advertise = mp->no_advertise == 1;
1220   off_link = mp->off_link == 1;
1221   no_autoconfig = mp->no_autoconfig == 1;
1222   no_onlink = mp->no_onlink == 1;
1223
1224   rv = ip6_neighbor_ra_prefix (vm, ntohl (mp->sw_if_index),
1225                                (ip6_address_t *) mp->address,
1226                                mp->address_length, use_default,
1227                                ntohl (mp->val_lifetime),
1228                                ntohl (mp->pref_lifetime), no_advertise,
1229                                off_link, no_autoconfig, no_onlink, is_no);
1230
1231   BAD_SW_IF_INDEX_LABEL;
1232   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
1233 }
1234
1235 static void
1236   vl_api_sw_interface_ip6_enable_disable_t_handler
1237   (vl_api_sw_interface_ip6_enable_disable_t * mp)
1238 {
1239   vlib_main_t *vm = vlib_get_main ();
1240   vl_api_sw_interface_ip6_enable_disable_reply_t *rmp;
1241   vnet_main_t *vnm = vnet_get_main ();
1242   int rv = 0;
1243   clib_error_t *error;
1244
1245   vnm->api_errno = 0;
1246
1247   VALIDATE_SW_IF_INDEX (mp);
1248
1249   error =
1250     (mp->enable == 1) ? enable_ip6_interface (vm,
1251                                               ntohl (mp->sw_if_index)) :
1252     disable_ip6_interface (vm, ntohl (mp->sw_if_index));
1253
1254   if (error)
1255     {
1256       clib_error_report (error);
1257       rv = VNET_API_ERROR_UNSPECIFIED;
1258     }
1259   else
1260     {
1261       rv = vnm->api_errno;
1262     }
1263
1264   BAD_SW_IF_INDEX_LABEL;
1265
1266   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
1267 }
1268
1269 static void
1270   vl_api_sw_interface_ip6_set_link_local_address_t_handler
1271   (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
1272 {
1273   vlib_main_t *vm = vlib_get_main ();
1274   vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
1275   int rv = 0;
1276   clib_error_t *error;
1277   vnet_main_t *vnm = vnet_get_main ();
1278
1279   vnm->api_errno = 0;
1280
1281   VALIDATE_SW_IF_INDEX (mp);
1282
1283   error = set_ip6_link_local_address (vm,
1284                                       ntohl (mp->sw_if_index),
1285                                       (ip6_address_t *) mp->address);
1286   if (error)
1287     {
1288       clib_error_report (error);
1289       rv = VNET_API_ERROR_UNSPECIFIED;
1290     }
1291   else
1292     {
1293       rv = vnm->api_errno;
1294     }
1295
1296   BAD_SW_IF_INDEX_LABEL;
1297
1298   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
1299 }
1300
1301 void
1302 vl_mfib_signal_send_one (unix_shared_memory_queue_t * q,
1303                          u32 context, const mfib_signal_t * mfs)
1304 {
1305   vl_api_mfib_signal_details_t *mp;
1306   mfib_prefix_t prefix;
1307   mfib_table_t *mfib;
1308   mfib_itf_t *mfi;
1309
1310   mp = vl_msg_api_alloc (sizeof (*mp));
1311
1312   memset (mp, 0, sizeof (*mp));
1313   mp->_vl_msg_id = ntohs (VL_API_MFIB_SIGNAL_DETAILS);
1314   mp->context = context;
1315
1316   mfi = mfib_itf_get (mfs->mfs_itf);
1317   mfib_entry_get_prefix (mfs->mfs_entry, &prefix);
1318   mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry),
1319                          prefix.fp_proto);
1320   mp->table_id = ntohl (mfib->mft_table_id);
1321   mp->sw_if_index = ntohl (mfi->mfi_sw_if_index);
1322
1323   if (FIB_PROTOCOL_IP4 == prefix.fp_proto)
1324     {
1325       mp->grp_address_len = ntohs (prefix.fp_len);
1326
1327       memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4);
1328       if (prefix.fp_len > 32)
1329         {
1330           memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4);
1331         }
1332     }
1333   else
1334     {
1335       mp->grp_address_len = ntohs (prefix.fp_len);
1336
1337       ASSERT (0);
1338     }
1339
1340   if (0 != mfs->mfs_buffer_len)
1341     {
1342       mp->ip_packet_len = ntohs (mfs->mfs_buffer_len);
1343
1344       memcpy (mp->ip_packet_data, mfs->mfs_buffer, mfs->mfs_buffer_len);
1345     }
1346   else
1347     {
1348       mp->ip_packet_len = 0;
1349     }
1350
1351   vl_msg_api_send_shmem (q, (u8 *) & mp);
1352 }
1353
1354 static void
1355 vl_api_mfib_signal_dump_t_handler (vl_api_mfib_signal_dump_t * mp)
1356 {
1357   unix_shared_memory_queue_t *q;
1358
1359   q = vl_api_client_index_to_input_queue (mp->client_index);
1360   if (q == 0)
1361     {
1362       return;
1363     }
1364
1365   while (q->cursize < q->maxsize && mfib_signal_send_one (q, mp->context))
1366     ;
1367 }
1368
1369 #define vl_msg_name_crc_list
1370 #include <vnet/ip/ip.api.h>
1371 #undef vl_msg_name_crc_list
1372
1373 static void
1374 setup_message_id_table (api_main_t * am)
1375 {
1376 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1377   foreach_vl_msg_name_crc_ip;
1378 #undef _
1379 }
1380
1381 static clib_error_t *
1382 ip_api_hookup (vlib_main_t * vm)
1383 {
1384   api_main_t *am = &api_main;
1385
1386 #define _(N,n)                                                  \
1387     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1388                            vl_api_##n##_t_handler,              \
1389                            vl_noop_handler,                     \
1390                            vl_api_##n##_t_endian,               \
1391                            vl_api_##n##_t_print,                \
1392                            sizeof(vl_api_##n##_t), 1);
1393   foreach_ip_api_msg;
1394 #undef _
1395
1396   /*
1397    * Set up the (msg_name, crc, message-id) table
1398    */
1399   setup_message_id_table (am);
1400
1401   return 0;
1402 }
1403
1404 VLIB_API_INIT_FUNCTION (ip_api_hookup);
1405
1406 /*
1407  * fd.io coding-style-patch-verification: ON
1408  *
1409  * Local Variables:
1410  * eval: (c-set-style "gnu")
1411  * End:
1412  */