70b70fbc47757c2dc698a5cbae2c667c571ff990
[vpp.git] / vnet / vnet / interface_api.c
1 /*
2  *------------------------------------------------------------------
3  * interface_api.c - vnet interface 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/fib/fib_table.h>
28 #include <vnet/l2/l2_vtr.h>
29 #include <vnet/vnet_msg_enum.h>
30
31 #define vl_typedefs             /* define message structures */
32 #include <vnet/vnet_all_api_h.h>
33 #undef vl_typedefs
34
35 #define vl_endianfun            /* define message structures */
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_endianfun
38
39 /* instantiate all the print functions we know about */
40 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
41 #define vl_printfun
42 #include <vnet/vnet_all_api_h.h>
43 #undef vl_printfun
44
45 #include <vlibapi/api_helper_macros.h>
46
47 #define foreach_vpe_api_msg                                     \
48 _(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags)               \
49 _(SW_INTERFACE_SET_MTU, sw_interface_set_mtu)                   \
50 _(WANT_INTERFACE_EVENTS, want_interface_events)                 \
51 _(SW_INTERFACE_DUMP, sw_interface_dump)                         \
52 _(SW_INTERFACE_DETAILS, sw_interface_details)                   \
53 _(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address)   \
54 _(SW_INTERFACE_SET_TABLE, sw_interface_set_table)               \
55 _(SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered)     \
56 _(SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats)           \
57 _(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del)
58
59 static void
60 vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp)
61 {
62   vl_api_sw_interface_set_flags_reply_t *rmp;
63   vnet_main_t *vnm = vnet_get_main ();
64   int rv = 0;
65   clib_error_t *error;
66   u16 flags;
67
68   VALIDATE_SW_IF_INDEX (mp);
69
70   flags = mp->admin_up_down ? VNET_SW_INTERFACE_FLAG_ADMIN_UP : 0;
71
72   error = vnet_sw_interface_set_flags (vnm, ntohl (mp->sw_if_index), flags);
73   if (error)
74     {
75       rv = -1;
76       clib_error_report (error);
77     }
78
79   BAD_SW_IF_INDEX_LABEL;
80   REPLY_MACRO (VL_API_SW_INTERFACE_SET_FLAGS_REPLY);
81 }
82
83 static void
84 vl_api_sw_interface_set_mtu_t_handler (vl_api_sw_interface_set_mtu_t * mp)
85 {
86   vl_api_sw_interface_set_mtu_reply_t *rmp;
87   vnet_main_t *vnm = vnet_get_main ();
88   u32 flags = ETHERNET_INTERFACE_FLAG_MTU;
89   u32 sw_if_index = ntohl (mp->sw_if_index);
90   u16 mtu = ntohs (mp->mtu);
91   ethernet_main_t *em = &ethernet_main;
92   int rv = 0;
93
94   VALIDATE_SW_IF_INDEX (mp);
95
96   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, sw_if_index);
97   ethernet_interface_t *eif = ethernet_get_interface (em, sw_if_index);
98
99   if (!eif)
100     {
101       rv = VNET_API_ERROR_FEATURE_DISABLED;
102       goto bad_sw_if_index;
103     }
104
105   if (mtu < hi->min_supported_packet_bytes)
106     {
107       rv = VNET_API_ERROR_INVALID_VALUE;
108       goto bad_sw_if_index;
109     }
110
111   if (mtu > hi->max_supported_packet_bytes)
112     {
113       rv = VNET_API_ERROR_INVALID_VALUE;
114       goto bad_sw_if_index;
115     }
116
117   if (hi->max_packet_bytes != mtu)
118     {
119       hi->max_packet_bytes = mtu;
120       ethernet_set_flags (vnm, sw_if_index, flags);
121     }
122
123   BAD_SW_IF_INDEX_LABEL;
124   REPLY_MACRO (VL_API_SW_INTERFACE_SET_MTU_REPLY);
125 }
126
127 static void
128 send_sw_interface_details (vpe_api_main_t * am,
129                            unix_shared_memory_queue_t * q,
130                            vnet_sw_interface_t * swif,
131                            u8 * interface_name, u32 context)
132 {
133   vl_api_sw_interface_details_t *mp;
134   vnet_main_t *vnm = vnet_get_main ();
135   vnet_hw_interface_t *hi;
136   u8 *tag;
137
138   hi = vnet_get_sup_hw_interface (am->vnet_main, swif->sw_if_index);
139
140   mp = vl_msg_api_alloc (sizeof (*mp));
141   memset (mp, 0, sizeof (*mp));
142   mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_DETAILS);
143   mp->sw_if_index = ntohl (swif->sw_if_index);
144   mp->sup_sw_if_index = ntohl (swif->sup_sw_if_index);
145   mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0;
146   mp->link_up_down = (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ? 1 : 0;
147   mp->link_duplex = ((hi->flags & VNET_HW_INTERFACE_FLAG_DUPLEX_MASK) >>
148                      VNET_HW_INTERFACE_FLAG_DUPLEX_SHIFT);
149   mp->link_speed = ((hi->flags & VNET_HW_INTERFACE_FLAG_SPEED_MASK) >>
150                     VNET_HW_INTERFACE_FLAG_SPEED_SHIFT);
151   mp->link_mtu = ntohs (hi->max_packet_bytes);
152   mp->context = context;
153
154   strncpy ((char *) mp->interface_name,
155            (char *) interface_name, ARRAY_LEN (mp->interface_name) - 1);
156
157   /* Send the L2 address for ethernet physical intfcs */
158   if (swif->sup_sw_if_index == swif->sw_if_index
159       && hi->hw_class_index == ethernet_hw_interface_class.index)
160     {
161       ethernet_main_t *em = ethernet_get_main (am->vlib_main);
162       ethernet_interface_t *ei;
163
164       ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
165       ASSERT (sizeof (mp->l2_address) >= sizeof (ei->address));
166       clib_memcpy (mp->l2_address, ei->address, sizeof (ei->address));
167       mp->l2_address_length = ntohl (sizeof (ei->address));
168     }
169   else if (swif->sup_sw_if_index != swif->sw_if_index)
170     {
171       vnet_sub_interface_t *sub = &swif->sub;
172       mp->sub_id = ntohl (sub->id);
173       mp->sub_dot1ad = sub->eth.flags.dot1ad;
174       mp->sub_number_of_tags =
175         sub->eth.flags.one_tag + sub->eth.flags.two_tags * 2;
176       mp->sub_outer_vlan_id = ntohs (sub->eth.outer_vlan_id);
177       mp->sub_inner_vlan_id = ntohs (sub->eth.inner_vlan_id);
178       mp->sub_exact_match = sub->eth.flags.exact_match;
179       mp->sub_default = sub->eth.flags.default_sub;
180       mp->sub_outer_vlan_id_any = sub->eth.flags.outer_vlan_id_any;
181       mp->sub_inner_vlan_id_any = sub->eth.flags.inner_vlan_id_any;
182
183       /* vlan tag rewrite data */
184       u32 vtr_op = L2_VTR_DISABLED;
185       u32 vtr_push_dot1q = 0, vtr_tag1 = 0, vtr_tag2 = 0;
186
187       if (l2vtr_get (am->vlib_main, am->vnet_main, swif->sw_if_index,
188                      &vtr_op, &vtr_push_dot1q, &vtr_tag1, &vtr_tag2) != 0)
189         {
190           // error - default to disabled
191           mp->vtr_op = ntohl (L2_VTR_DISABLED);
192           clib_warning ("cannot get vlan tag rewrite for sw_if_index %d",
193                         swif->sw_if_index);
194         }
195       else
196         {
197           mp->vtr_op = ntohl (vtr_op);
198           mp->vtr_push_dot1q = ntohl (vtr_push_dot1q);
199           mp->vtr_tag1 = ntohl (vtr_tag1);
200           mp->vtr_tag2 = ntohl (vtr_tag2);
201         }
202     }
203
204   tag = vnet_get_sw_interface_tag (vnm, swif->sw_if_index);
205   if (tag)
206     strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
207
208   vl_msg_api_send_shmem (q, (u8 *) & mp);
209 }
210
211 static void
212 vl_api_sw_interface_dump_t_handler (vl_api_sw_interface_dump_t * mp)
213 {
214   vpe_api_main_t *am = &vpe_api_main;
215   vnet_sw_interface_t *swif;
216   vnet_interface_main_t *im = &am->vnet_main->interface_main;
217   u8 *filter_string = 0, *name_string = 0;
218   unix_shared_memory_queue_t *q;
219   char *strcasestr (char *, char *);    /* lnx hdr file botch */
220
221   q = vl_api_client_index_to_input_queue (mp->client_index);
222
223   if (q == 0)
224     return;
225
226   if (mp->name_filter_valid)
227     {
228       mp->name_filter[ARRAY_LEN (mp->name_filter) - 1] = 0;
229       filter_string = format (0, "%s%c", mp->name_filter, 0);
230     }
231
232   /* *INDENT-OFF* */
233   pool_foreach (swif, im->sw_interfaces,
234   ({
235     name_string = format (name_string, "%U%c",
236                           format_vnet_sw_interface_name,
237                           am->vnet_main, swif, 0);
238
239     if (mp->name_filter_valid == 0 ||
240         strcasestr((char *) name_string, (char *) filter_string)) {
241
242       send_sw_interface_details (am, q, swif, name_string, mp->context);
243     }
244     _vec_len (name_string) = 0;
245   }));
246   /* *INDENT-ON* */
247
248   vec_free (name_string);
249   vec_free (filter_string);
250 }
251
252 static void
253   vl_api_sw_interface_add_del_address_t_handler
254   (vl_api_sw_interface_add_del_address_t * mp)
255 {
256   vlib_main_t *vm = vlib_get_main ();
257   vl_api_sw_interface_add_del_address_reply_t *rmp;
258   int rv = 0;
259   u32 is_del;
260
261   VALIDATE_SW_IF_INDEX (mp);
262
263   is_del = mp->is_add == 0;
264
265   if (mp->del_all)
266     ip_del_all_interface_addresses (vm, ntohl (mp->sw_if_index));
267   else if (mp->is_ipv6)
268     ip6_add_del_interface_address (vm, ntohl (mp->sw_if_index),
269                                    (void *) mp->address,
270                                    mp->address_length, is_del);
271   else
272     ip4_add_del_interface_address (vm, ntohl (mp->sw_if_index),
273                                    (void *) mp->address,
274                                    mp->address_length, is_del);
275
276   BAD_SW_IF_INDEX_LABEL;
277
278   REPLY_MACRO (VL_API_SW_INTERFACE_ADD_DEL_ADDRESS_REPLY);
279 }
280
281 void stats_dslock_with_hint (int hint, int tag) __attribute__ ((weak));
282 void
283 stats_dslock_with_hint (int hint, int tag)
284 {
285 }
286
287 void stats_dsunlock (void) __attribute__ ((weak));
288 void
289 stats_dsunlock (void)
290 {
291 }
292
293 static void
294 vl_api_sw_interface_set_table_t_handler (vl_api_sw_interface_set_table_t * mp)
295 {
296   int rv = 0;
297   u32 table_id = ntohl (mp->vrf_id);
298   u32 sw_if_index = ntohl (mp->sw_if_index);
299   vl_api_sw_interface_set_table_reply_t *rmp;
300   u32 fib_index;
301
302   VALIDATE_SW_IF_INDEX (mp);
303
304   stats_dslock_with_hint (1 /* release hint */ , 4 /* tag */ );
305
306   if (mp->is_ipv6)
307     {
308       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
309                                                      table_id);
310
311       vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
312       ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
313     }
314   else
315     {
316
317       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
318                                                      table_id);
319
320       vec_validate (ip4_main.fib_index_by_sw_if_index, sw_if_index);
321       ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
322     }
323   stats_dsunlock ();
324
325   BAD_SW_IF_INDEX_LABEL;
326
327   REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY);
328 }
329
330 static void vl_api_sw_interface_set_unnumbered_t_handler
331   (vl_api_sw_interface_set_unnumbered_t * mp)
332 {
333   vl_api_sw_interface_set_unnumbered_reply_t *rmp;
334   int rv = 0;
335   vnet_sw_interface_t *si;
336   vnet_main_t *vnm = vnet_get_main ();
337   u32 sw_if_index, unnumbered_sw_if_index;
338
339   sw_if_index = ntohl (mp->sw_if_index);
340   unnumbered_sw_if_index = ntohl (mp->unnumbered_sw_if_index);
341
342   /*
343    * The API message field names are backwards from
344    * the underlying data structure names.
345    * It's not worth changing them now.
346    */
347   if (pool_is_free_index (vnm->interface_main.sw_interfaces,
348                           unnumbered_sw_if_index))
349     {
350       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
351       goto done;
352     }
353
354   /* Only check the "use loop0" field when setting the binding */
355   if (mp->is_add &&
356       pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
357     {
358       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
359       goto done;
360     }
361
362   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
363
364   if (mp->is_add)
365     {
366       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
367       si->unnumbered_sw_if_index = sw_if_index;
368       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 1);
369       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 1);
370     }
371   else
372     {
373       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
374       si->unnumbered_sw_if_index = (u32) ~ 0;
375       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 0);
376       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 0);
377     }
378
379 done:
380   REPLY_MACRO (VL_API_SW_INTERFACE_SET_UNNUMBERED_REPLY);
381 }
382
383 static void
384 vl_api_sw_interface_clear_stats_t_handler (vl_api_sw_interface_clear_stats_t *
385                                            mp)
386 {
387   vl_api_sw_interface_clear_stats_reply_t *rmp;
388
389   vnet_main_t *vnm = vnet_get_main ();
390   vnet_interface_main_t *im = &vnm->interface_main;
391   vlib_simple_counter_main_t *sm;
392   vlib_combined_counter_main_t *cm;
393   static vnet_main_t **my_vnet_mains;
394   int i, j, n_counters;
395   int rv = 0;
396
397   if (mp->sw_if_index != ~0)
398     VALIDATE_SW_IF_INDEX (mp);
399
400   vec_reset_length (my_vnet_mains);
401
402   for (i = 0; i < vec_len (vnet_mains); i++)
403     {
404       if (vnet_mains[i])
405         vec_add1 (my_vnet_mains, vnet_mains[i]);
406     }
407
408   if (vec_len (vnet_mains) == 0)
409     vec_add1 (my_vnet_mains, vnm);
410
411   n_counters = vec_len (im->combined_sw_if_counters);
412
413   for (j = 0; j < n_counters; j++)
414     {
415       for (i = 0; i < vec_len (my_vnet_mains); i++)
416         {
417           im = &my_vnet_mains[i]->interface_main;
418           cm = im->combined_sw_if_counters + j;
419           if (mp->sw_if_index == (u32) ~ 0)
420             vlib_clear_combined_counters (cm);
421           else
422             vlib_zero_combined_counter (cm, ntohl (mp->sw_if_index));
423         }
424     }
425
426   n_counters = vec_len (im->sw_if_counters);
427
428   for (j = 0; j < n_counters; j++)
429     {
430       for (i = 0; i < vec_len (my_vnet_mains); i++)
431         {
432           im = &my_vnet_mains[i]->interface_main;
433           sm = im->sw_if_counters + j;
434           if (mp->sw_if_index == (u32) ~ 0)
435             vlib_clear_simple_counters (sm);
436           else
437             vlib_zero_simple_counter (sm, ntohl (mp->sw_if_index));
438         }
439     }
440
441   BAD_SW_IF_INDEX_LABEL;
442
443   REPLY_MACRO (VL_API_SW_INTERFACE_CLEAR_STATS_REPLY);
444 }
445
446 #define API_LINK_STATE_EVENT 1
447 #define API_ADMIN_UP_DOWN_EVENT 2
448
449 static int
450 event_data_cmp (void *a1, void *a2)
451 {
452   uword *e1 = a1;
453   uword *e2 = a2;
454
455   return (word) e1[0] - (word) e2[0];
456 }
457
458 static void
459 send_sw_interface_flags (vpe_api_main_t * am,
460                          unix_shared_memory_queue_t * q,
461                          vnet_sw_interface_t * swif)
462 {
463   vl_api_sw_interface_set_flags_t *mp;
464   vnet_main_t *vnm = am->vnet_main;
465
466   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm,
467                                                        swif->sw_if_index);
468   mp = vl_msg_api_alloc (sizeof (*mp));
469   memset (mp, 0, sizeof (*mp));
470   mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_SET_FLAGS);
471   mp->sw_if_index = ntohl (swif->sw_if_index);
472
473   mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0;
474   mp->link_up_down = (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ? 1 : 0;
475   vl_msg_api_send_shmem (q, (u8 *) & mp);
476 }
477
478 static uword
479 link_state_process (vlib_main_t * vm,
480                     vlib_node_runtime_t * rt, vlib_frame_t * f)
481 {
482   vpe_api_main_t *vam = &vpe_api_main;
483   vnet_main_t *vnm = vam->vnet_main;
484   vnet_sw_interface_t *swif;
485   uword *event_data = 0;
486   vpe_client_registration_t *reg;
487   int i;
488   u32 prev_sw_if_index;
489   unix_shared_memory_queue_t *q;
490
491   vam->link_state_process_up = 1;
492
493   while (1)
494     {
495       vlib_process_wait_for_event (vm);
496
497       /* Unified list of changed link or admin state sw_if_indices */
498       vlib_process_get_events_with_type
499         (vm, &event_data, API_LINK_STATE_EVENT);
500       vlib_process_get_events_with_type
501         (vm, &event_data, API_ADMIN_UP_DOWN_EVENT);
502
503       /* Sort, so we can eliminate duplicates */
504       vec_sort_with_function (event_data, event_data_cmp);
505
506       prev_sw_if_index = ~0;
507
508       for (i = 0; i < vec_len (event_data); i++)
509         {
510           /* Only one message per swif */
511           if (prev_sw_if_index == event_data[i])
512             continue;
513           prev_sw_if_index = event_data[i];
514
515           /* *INDENT-OFF* */
516           pool_foreach(reg, vam->interface_events_registrations,
517           ({
518             q = vl_api_client_index_to_input_queue (reg->client_index);
519             if (q)
520               {
521                 /* sw_interface may be deleted already */
522                 if (!pool_is_free_index (vnm->interface_main.sw_interfaces,
523                                          event_data[i]))
524                   {
525                     swif = vnet_get_sw_interface (vnm, event_data[i]);
526                     send_sw_interface_flags (vam, q, swif);
527                   }
528               }
529           }));
530           /* *INDENT-ON* */
531         }
532       vec_reset_length (event_data);
533     }
534
535   return 0;
536 }
537
538 static clib_error_t *link_up_down_function (vnet_main_t * vm, u32 hw_if_index,
539                                             u32 flags);
540 static clib_error_t *admin_up_down_function (vnet_main_t * vm,
541                                              u32 hw_if_index, u32 flags);
542
543 /* *INDENT-OFF* */
544 VLIB_REGISTER_NODE (link_state_process_node,static) = {
545   .function = link_state_process,
546   .type = VLIB_NODE_TYPE_PROCESS,
547   .name = "vpe-link-state-process",
548 };
549 /* *INDENT-ON* */
550
551 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (admin_up_down_function);
552 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (link_up_down_function);
553
554 static clib_error_t *
555 link_up_down_function (vnet_main_t * vm, u32 hw_if_index, u32 flags)
556 {
557   vpe_api_main_t *vam = &vpe_api_main;
558   vnet_hw_interface_t *hi = vnet_get_hw_interface (vm, hw_if_index);
559
560   if (vam->link_state_process_up)
561     vlib_process_signal_event (vam->vlib_main,
562                                link_state_process_node.index,
563                                API_LINK_STATE_EVENT, hi->sw_if_index);
564   return 0;
565 }
566
567 static clib_error_t *
568 admin_up_down_function (vnet_main_t * vm, u32 sw_if_index, u32 flags)
569 {
570   vpe_api_main_t *vam = &vpe_api_main;
571
572   /*
573    * Note: it's perfectly fair to set a subif admin up / admin down.
574    * Note the subtle distinction between this routine and the previous
575    * routine.
576    */
577   if (vam->link_state_process_up)
578     vlib_process_signal_event (vam->vlib_main,
579                                link_state_process_node.index,
580                                API_ADMIN_UP_DOWN_EVENT, sw_if_index);
581   return 0;
582 }
583
584 static void vl_api_sw_interface_tag_add_del_t_handler
585   (vl_api_sw_interface_tag_add_del_t * mp)
586 {
587   vnet_main_t *vnm = vnet_get_main ();
588   vl_api_sw_interface_tag_add_del_reply_t *rmp;
589   int rv = 0;
590   u8 *tag;
591   u32 sw_if_index = ntohl (mp->sw_if_index);
592
593   VALIDATE_SW_IF_INDEX (mp);
594
595   if (mp->is_add)
596     {
597       if (mp->tag[0] == 0)
598         {
599           rv = VNET_API_ERROR_INVALID_VALUE;
600           goto out;
601         }
602
603       mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
604       tag = format (0, "%s%c", mp->tag, 0);
605       vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
606     }
607   else
608     vnet_clear_sw_interface_tag (vnm, sw_if_index);
609
610   BAD_SW_IF_INDEX_LABEL;
611 out:
612   REPLY_MACRO (VL_API_SW_INTERFACE_TAG_ADD_DEL_REPLY);
613 }
614
615 static void
616 vl_api_sw_interface_details_t_handler (vl_api_sw_interface_details_t * mp)
617 {
618   clib_warning ("BUG");
619 }
620
621 /*
622  * vpe_api_hookup
623  * Add vpe's API message handlers to the table.
624  * vlib has alread mapped shared memory and
625  * added the client registration handlers.
626  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
627  */
628 #define vl_msg_name_crc_list
629 #include <vnet/vnet_all_api_h.h>
630 #undef vl_msg_name_crc_list
631
632 static void
633 setup_message_id_table (api_main_t * am)
634 {
635 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
636   foreach_vl_msg_name_crc_interface;
637 #undef _
638 }
639
640 pub_sub_handler (interface_events, INTERFACE_EVENTS);
641
642 static clib_error_t *
643 interface_api_hookup (vlib_main_t * vm)
644 {
645   api_main_t *am = &api_main;
646
647 #define _(N,n)                                                  \
648     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
649                            vl_api_##n##_t_handler,              \
650                            vl_noop_handler,                     \
651                            vl_api_##n##_t_endian,               \
652                            vl_api_##n##_t_print,                \
653                            sizeof(vl_api_##n##_t), 1);
654   foreach_vpe_api_msg;
655 #undef _
656
657   /*
658    * Set up the (msg_name, crc, message-id) table
659    */
660   setup_message_id_table (am);
661
662   return 0;
663 }
664
665 VLIB_API_INIT_FUNCTION (interface_api_hookup);
666
667 /*
668  * fd.io coding-style-patch-verification: ON
669  *
670  * Local Variables:
671  * eval: (c-set-style "gnu")
672  * End:
673  */