classify: API cleanup
[vpp.git] / src / vnet / classify / classify_api.c
1 /*
2  *------------------------------------------------------------------
3  * classify_api.c - classify 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
26 #include <vnet/classify/vnet_classify.h>
27 #include <vnet/classify/in_out_acl.h>
28 #include <vnet/classify/policer_classify.h>
29 #include <vnet/classify/flow_classify.h>
30 #include <vnet/l2/l2_classify.h>
31
32 #include <vnet/vnet_msg_enum.h>
33
34 #define vl_typedefs             /* define message structures */
35 #include <vnet/vnet_all_api_h.h>
36 #undef vl_typedefs
37
38 #define vl_endianfun            /* define message structures */
39 #include <vnet/vnet_all_api_h.h>
40 #undef vl_endianfun
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <vnet/vnet_all_api_h.h>
46 #undef vl_printfun
47
48 #include <vlibapi/api_helper_macros.h>
49
50 #define foreach_vpe_api_msg                                             \
51 _(CLASSIFY_ADD_DEL_TABLE, classify_add_del_table)                       \
52 _(CLASSIFY_ADD_DEL_SESSION, classify_add_del_session)                   \
53 _(CLASSIFY_TABLE_IDS,classify_table_ids)                                \
54 _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface)             \
55 _(CLASSIFY_TABLE_INFO,classify_table_info)                              \
56 _(CLASSIFY_SESSION_DUMP,classify_session_dump)                          \
57 _(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface)       \
58 _(POLICER_CLASSIFY_DUMP, policer_classify_dump)                         \
59 _(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface)             \
60 _(FLOW_CLASSIFY_DUMP, flow_classify_dump)                               \
61 _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface)                     \
62 _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table)     \
63 _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables)   \
64 _(OUTPUT_ACL_SET_INTERFACE, output_acl_set_interface)
65
66 #define foreach_classify_add_del_table_field    \
67 _(table_index)                                  \
68 _(nbuckets)                                     \
69 _(memory_size)                                  \
70 _(skip_n_vectors)                               \
71 _(match_n_vectors)                              \
72 _(next_table_index)                             \
73 _(miss_next_index)                              \
74 _(mask_len)
75
76 static void vl_api_classify_add_del_table_t_handler
77   (vl_api_classify_add_del_table_t * mp)
78 {
79   vl_api_classify_add_del_table_reply_t *rmp;
80   vnet_classify_main_t *cm = &vnet_classify_main;
81   vnet_classify_table_t *t;
82   int rv;
83
84 #define _(a) u32 a;
85   foreach_classify_add_del_table_field;
86 #undef _
87
88 #define _(a) a = ntohl(mp->a);
89   foreach_classify_add_del_table_field;
90 #undef _
91
92   if (mask_len != match_n_vectors * sizeof (u32x4))
93     {
94       rv = VNET_API_ERROR_INVALID_VALUE;
95       goto out;
96     }
97
98   /* The underlying API fails silently, on purpose, so check here */
99   if (mp->is_add == 0)          /* delete */
100     {
101       if (pool_is_free_index (cm->tables, table_index))
102         {
103           rv = VNET_API_ERROR_NO_SUCH_TABLE;
104           goto out;
105         }
106     }
107   else                          /* add or update */
108     {
109       if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
110         table_index = ~0;
111     }
112
113   u8 current_data_flag = mp->current_data_flag;
114   i16 current_data_offset = clib_net_to_host_i16 (mp->current_data_offset);
115
116   rv = vnet_classify_add_del_table
117     (cm, mp->mask, nbuckets, memory_size,
118      skip_n_vectors, match_n_vectors,
119      next_table_index, miss_next_index, &table_index,
120      current_data_flag, current_data_offset, mp->is_add, mp->del_chain);
121
122 out:
123   /* *INDENT-OFF* */
124   REPLY_MACRO2(VL_API_CLASSIFY_ADD_DEL_TABLE_REPLY,
125   ({
126     if (rv == 0 && mp->is_add)
127       {
128         t = pool_elt_at_index (cm->tables, table_index);
129         rmp->skip_n_vectors = htonl(t->skip_n_vectors);
130         rmp->match_n_vectors = htonl(t->match_n_vectors);
131         rmp->new_table_index = htonl(table_index);
132       }
133     else
134       {
135         rmp->skip_n_vectors = ~0;
136         rmp->match_n_vectors = ~0;
137         rmp->new_table_index = ~0;
138       }
139   }));
140   /* *INDENT-ON* */
141 }
142
143 static void vl_api_classify_add_del_session_t_handler
144   (vl_api_classify_add_del_session_t * mp)
145 {
146   vnet_classify_main_t *cm = &vnet_classify_main;
147   vl_api_classify_add_del_session_reply_t *rmp;
148   int rv;
149   u32 table_index, hit_next_index, opaque_index, metadata, match_len;
150   i32 advance;
151   u8 action;
152   vnet_classify_table_t *t;
153
154   table_index = ntohl (mp->table_index);
155   hit_next_index = ntohl (mp->hit_next_index);
156   opaque_index = ntohl (mp->opaque_index);
157   advance = ntohl (mp->advance);
158   action = mp->action;
159   metadata = ntohl (mp->metadata);
160   match_len = ntohl (mp->match_len);
161
162   if (pool_is_free_index (cm->tables, table_index))
163     {
164       rv = VNET_API_ERROR_NO_SUCH_TABLE;
165       goto out;
166     }
167
168   t = pool_elt_at_index (cm->tables, table_index);
169
170   if (match_len != (t->skip_n_vectors + t->match_n_vectors) * sizeof (u32x4))
171     {
172       rv = VNET_API_ERROR_INVALID_VALUE;
173       goto out;
174     }
175
176   rv = vnet_classify_add_del_session
177     (cm, table_index, mp->match, hit_next_index, opaque_index,
178      advance, action, metadata, mp->is_add);
179
180 out:
181   REPLY_MACRO (VL_API_CLASSIFY_ADD_DEL_SESSION_REPLY);
182 }
183
184 static void
185   vl_api_policer_classify_set_interface_t_handler
186   (vl_api_policer_classify_set_interface_t * mp)
187 {
188   vlib_main_t *vm = vlib_get_main ();
189   vl_api_policer_classify_set_interface_reply_t *rmp;
190   int rv;
191   u32 sw_if_index, ip4_table_index, ip6_table_index, l2_table_index;
192
193   ip4_table_index = ntohl (mp->ip4_table_index);
194   ip6_table_index = ntohl (mp->ip6_table_index);
195   l2_table_index = ntohl (mp->l2_table_index);
196   sw_if_index = ntohl (mp->sw_if_index);
197
198   VALIDATE_SW_IF_INDEX (mp);
199
200   rv = vnet_set_policer_classify_intfc (vm, sw_if_index, ip4_table_index,
201                                         ip6_table_index, l2_table_index,
202                                         mp->is_add);
203
204   BAD_SW_IF_INDEX_LABEL;
205
206   REPLY_MACRO (VL_API_POLICER_CLASSIFY_SET_INTERFACE_REPLY);
207 }
208
209 static void
210 send_policer_classify_details (u32 sw_if_index,
211                                u32 table_index, vl_api_registration_t * reg,
212                                u32 context)
213 {
214   vl_api_policer_classify_details_t *mp;
215
216   mp = vl_msg_api_alloc (sizeof (*mp));
217   clib_memset (mp, 0, sizeof (*mp));
218   mp->_vl_msg_id = ntohs (VL_API_POLICER_CLASSIFY_DETAILS);
219   mp->context = context;
220   mp->sw_if_index = htonl (sw_if_index);
221   mp->table_index = htonl (table_index);
222
223   vl_api_send_msg (reg, (u8 *) mp);
224 }
225
226 static void
227 vl_api_policer_classify_dump_t_handler (vl_api_policer_classify_dump_t * mp)
228 {
229   vl_api_registration_t *reg;
230   policer_classify_main_t *pcm = &policer_classify_main;
231   u32 *vec_tbl;
232   int i;
233   u32 filter_sw_if_index;
234
235   reg = vl_api_client_index_to_registration (mp->client_index);
236   if (!reg)
237     return;
238
239   filter_sw_if_index = ntohl (mp->sw_if_index);
240   if (filter_sw_if_index != ~0)
241     vec_tbl =
242       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
243   else
244     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
245
246   if (vec_len (vec_tbl))
247     {
248       for (i = 0; i < vec_len (vec_tbl); i++)
249         {
250           if (vec_elt (vec_tbl, i) == ~0)
251             continue;
252
253           send_policer_classify_details (i, vec_elt (vec_tbl, i), reg,
254                                          mp->context);
255         }
256     }
257 }
258
259 static void
260 vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t * mp)
261 {
262   vl_api_registration_t *reg;
263
264   reg = vl_api_client_index_to_registration (mp->client_index);
265   if (!reg)
266     return;
267
268   vnet_classify_main_t *cm = &vnet_classify_main;
269   vnet_classify_table_t *t;
270   u32 *table_ids = 0;
271   u32 count;
272
273    /* *INDENT-OFF* */
274    pool_foreach (t, cm->tables,
275    ({
276      vec_add1 (table_ids, ntohl(t - cm->tables));
277    }));
278    /* *INDENT-ON* */
279   count = vec_len (table_ids);
280
281   vl_api_classify_table_ids_reply_t *rmp;
282   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
283   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_IDS_REPLY);
284   rmp->context = mp->context;
285   rmp->count = ntohl (count);
286   clib_memcpy (rmp->ids, table_ids, count * sizeof (u32));
287   rmp->retval = 0;
288
289   vl_api_send_msg (reg, (u8 *) rmp);
290
291   vec_free (table_ids);
292 }
293
294 static void
295   vl_api_classify_table_by_interface_t_handler
296   (vl_api_classify_table_by_interface_t * mp)
297 {
298   vl_api_classify_table_by_interface_reply_t *rmp;
299   int rv = 0;
300
301   u32 sw_if_index = ntohl (mp->sw_if_index);
302   u32 *acl = 0;
303
304   vec_validate (acl, IN_OUT_ACL_N_TABLES - 1);
305   vec_set (acl, ~0);
306
307   VALIDATE_SW_IF_INDEX (mp);
308
309   in_out_acl_main_t *am = &in_out_acl_main;
310
311   int if_idx;
312   u32 type;
313
314   for (type = 0; type < IN_OUT_ACL_N_TABLES; type++)
315     {
316       u32 *vec_tbl =
317         am->classify_table_index_by_sw_if_index[IN_OUT_ACL_INPUT_TABLE_GROUP]
318         [type];
319       if (vec_len (vec_tbl))
320         {
321           for (if_idx = 0; if_idx < vec_len (vec_tbl); if_idx++)
322             {
323               if (vec_elt (vec_tbl, if_idx) == ~0 || sw_if_index != if_idx)
324                 {
325                   continue;
326                 }
327               acl[type] = vec_elt (vec_tbl, if_idx);
328             }
329         }
330     }
331
332   BAD_SW_IF_INDEX_LABEL;
333
334    /* *INDENT-OFF* */
335    REPLY_MACRO2(VL_API_CLASSIFY_TABLE_BY_INTERFACE_REPLY,
336    ({
337      rmp->sw_if_index = ntohl(sw_if_index);
338      rmp->l2_table_id = ntohl(acl[IN_OUT_ACL_TABLE_L2]);
339      rmp->ip4_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP4]);
340      rmp->ip6_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP6]);
341    }));
342    /* *INDENT-ON* */
343   vec_free (acl);
344 }
345
346 static void
347 vl_api_classify_table_info_t_handler (vl_api_classify_table_info_t * mp)
348 {
349   vl_api_registration_t *reg;
350
351   reg = vl_api_client_index_to_registration (mp->client_index);
352   if (!reg)
353     return;
354
355   vl_api_classify_table_info_reply_t *rmp = 0;
356
357   vnet_classify_main_t *cm = &vnet_classify_main;
358   u32 table_id = ntohl (mp->table_id);
359   vnet_classify_table_t *t;
360
361    /* *INDENT-OFF* */
362    pool_foreach (t, cm->tables,
363    ({
364      if (table_id == t - cm->tables)
365        {
366          rmp = vl_msg_api_alloc_as_if_client
367            (sizeof (*rmp) + t->match_n_vectors * sizeof (u32x4));
368          rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_INFO_REPLY);
369          rmp->context = mp->context;
370          rmp->table_id = ntohl(table_id);
371          rmp->nbuckets = ntohl(t->nbuckets);
372          rmp->match_n_vectors = ntohl(t->match_n_vectors);
373          rmp->skip_n_vectors = ntohl(t->skip_n_vectors);
374          rmp->active_sessions = ntohl(t->active_elements);
375          rmp->next_table_index = ntohl(t->next_table_index);
376          rmp->miss_next_index = ntohl(t->miss_next_index);
377          rmp->mask_length = ntohl(t->match_n_vectors * sizeof (u32x4));
378          clib_memcpy(rmp->mask, t->mask, t->match_n_vectors * sizeof(u32x4));
379          rmp->retval = 0;
380          break;
381        }
382    }));
383    /* *INDENT-ON* */
384
385   if (rmp == 0)
386     {
387       rmp = vl_msg_api_alloc (sizeof (*rmp));
388       rmp->_vl_msg_id = ntohs ((VL_API_CLASSIFY_TABLE_INFO_REPLY));
389       rmp->context = mp->context;
390       rmp->retval = ntohl (VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND);
391     }
392
393   vl_api_send_msg (reg, (u8 *) rmp);
394 }
395
396 static void
397 send_classify_session_details (vl_api_registration_t * reg,
398                                u32 table_id,
399                                u32 match_length,
400                                vnet_classify_entry_t * e, u32 context)
401 {
402   vl_api_classify_session_details_t *rmp;
403
404   rmp = vl_msg_api_alloc (sizeof (*rmp));
405   clib_memset (rmp, 0, sizeof (*rmp));
406   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_SESSION_DETAILS);
407   rmp->context = context;
408   rmp->table_id = ntohl (table_id);
409   rmp->hit_next_index = ntohl (e->next_index);
410   rmp->advance = ntohl (e->advance);
411   rmp->opaque_index = ntohl (e->opaque_index);
412   rmp->match_length = ntohl (match_length);
413   clib_memcpy (rmp->match, e->key, match_length);
414
415   vl_api_send_msg (reg, (u8 *) rmp);
416 }
417
418 static void
419 vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t * mp)
420 {
421   vnet_classify_main_t *cm = &vnet_classify_main;
422   vl_api_registration_t *reg;
423
424   u32 table_id = ntohl (mp->table_id);
425   vnet_classify_table_t *t;
426
427   reg = vl_api_client_index_to_registration (mp->client_index);
428   if (!reg)
429     return;
430
431   /* *INDENT-OFF* */
432   pool_foreach (t, cm->tables,
433   ({
434     if (table_id == t - cm->tables)
435       {
436         vnet_classify_bucket_t * b;
437         vnet_classify_entry_t * v, * save_v;
438         int i, j, k;
439
440         for (i = 0; i < t->nbuckets; i++)
441           {
442             b = &t->buckets [i];
443             if (b->offset == 0)
444               continue;
445
446             save_v = vnet_classify_get_entry (t, b->offset);
447             for (j = 0; j < (1<<b->log2_pages); j++)
448               {
449                 for (k = 0; k < t->entries_per_page; k++)
450                   {
451                     v = vnet_classify_entry_at_index
452                       (t, save_v, j*t->entries_per_page + k);
453                     if (vnet_classify_entry_is_free (v))
454                       continue;
455
456                     send_classify_session_details
457                       (reg, table_id, t->match_n_vectors * sizeof (u32x4),
458                        v, mp->context);
459                   }
460               }
461           }
462         break;
463       }
464   }));
465   /* *INDENT-ON* */
466 }
467
468 static void
469   vl_api_flow_classify_set_interface_t_handler
470   (vl_api_flow_classify_set_interface_t * mp)
471 {
472   vlib_main_t *vm = vlib_get_main ();
473   vl_api_flow_classify_set_interface_reply_t *rmp;
474   int rv;
475   u32 sw_if_index, ip4_table_index, ip6_table_index;
476
477   ip4_table_index = ntohl (mp->ip4_table_index);
478   ip6_table_index = ntohl (mp->ip6_table_index);
479   sw_if_index = ntohl (mp->sw_if_index);
480
481   VALIDATE_SW_IF_INDEX (mp);
482
483   rv = vnet_set_flow_classify_intfc (vm, sw_if_index, ip4_table_index,
484                                      ip6_table_index, mp->is_add);
485
486   BAD_SW_IF_INDEX_LABEL;
487
488   REPLY_MACRO (VL_API_FLOW_CLASSIFY_SET_INTERFACE_REPLY);
489 }
490
491 static void
492 send_flow_classify_details (u32 sw_if_index,
493                             u32 table_index, vl_api_registration_t * reg,
494                             u32 context)
495 {
496   vl_api_flow_classify_details_t *mp;
497
498   mp = vl_msg_api_alloc (sizeof (*mp));
499   clib_memset (mp, 0, sizeof (*mp));
500   mp->_vl_msg_id = ntohs (VL_API_FLOW_CLASSIFY_DETAILS);
501   mp->context = context;
502   mp->sw_if_index = htonl (sw_if_index);
503   mp->table_index = htonl (table_index);
504
505   vl_api_send_msg (reg, (u8 *) mp);
506 }
507
508 static void
509 vl_api_flow_classify_dump_t_handler (vl_api_flow_classify_dump_t * mp)
510 {
511   vl_api_registration_t *reg;
512   flow_classify_main_t *pcm = &flow_classify_main;
513   u32 *vec_tbl;
514   int i;
515   u32 filter_sw_if_index;
516
517   reg = vl_api_client_index_to_registration (mp->client_index);
518   if (!reg)
519     return;
520
521   filter_sw_if_index = ntohl (mp->sw_if_index);
522   if (filter_sw_if_index != ~0)
523     vec_tbl =
524       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
525   else
526     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
527
528   if (vec_len (vec_tbl))
529     {
530       for (i = 0; i < vec_len (vec_tbl); i++)
531         {
532           if (vec_elt (vec_tbl, i) == ~0)
533             continue;
534
535           send_flow_classify_details (i, vec_elt (vec_tbl, i), reg,
536                                       mp->context);
537         }
538     }
539 }
540
541 static void vl_api_classify_set_interface_ip_table_t_handler
542   (vl_api_classify_set_interface_ip_table_t * mp)
543 {
544   vlib_main_t *vm = vlib_get_main ();
545   vl_api_classify_set_interface_ip_table_reply_t *rmp;
546   int rv;
547
548   VALIDATE_SW_IF_INDEX (mp);
549
550   u32 table_index = ntohl (mp->table_index);
551   u32 sw_if_index = ntohl (mp->sw_if_index);
552
553   if (mp->is_ipv6)
554     rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
555   else
556     rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
557
558   BAD_SW_IF_INDEX_LABEL;
559
560   REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY);
561 }
562
563 static void vl_api_classify_set_interface_l2_tables_t_handler
564   (vl_api_classify_set_interface_l2_tables_t * mp)
565 {
566   vl_api_classify_set_interface_l2_tables_reply_t *rmp;
567   int rv;
568   u32 sw_if_index, ip4_table_index, ip6_table_index, other_table_index;
569   int enable;
570
571   ip4_table_index = ntohl (mp->ip4_table_index);
572   ip6_table_index = ntohl (mp->ip6_table_index);
573   other_table_index = ntohl (mp->other_table_index);
574   sw_if_index = ntohl (mp->sw_if_index);
575
576   VALIDATE_SW_IF_INDEX (mp);
577
578   if (mp->is_input)
579     rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
580                                             ip6_table_index,
581                                             other_table_index);
582   else
583     rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
584                                              ip6_table_index,
585                                              other_table_index);
586
587   if (rv == 0)
588     {
589       if (ip4_table_index != ~0 || ip6_table_index != ~0
590           || other_table_index != ~0)
591         enable = 1;
592       else
593         enable = 0;
594
595       if (mp->is_input)
596         vnet_l2_input_classify_enable_disable (sw_if_index, enable);
597       else
598         vnet_l2_output_classify_enable_disable (sw_if_index, enable);
599     }
600
601   BAD_SW_IF_INDEX_LABEL;
602
603   REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY);
604 }
605
606 static void vl_api_input_acl_set_interface_t_handler
607   (vl_api_input_acl_set_interface_t * mp)
608 {
609   vlib_main_t *vm = vlib_get_main ();
610   vl_api_input_acl_set_interface_reply_t *rmp;
611   int rv;
612
613   VALIDATE_SW_IF_INDEX (mp);
614
615   u32 ip4_table_index = ntohl (mp->ip4_table_index);
616   u32 ip6_table_index = ntohl (mp->ip6_table_index);
617   u32 l2_table_index = ntohl (mp->l2_table_index);
618   u32 sw_if_index = ntohl (mp->sw_if_index);
619
620   rv = vnet_set_input_acl_intfc (vm, sw_if_index, ip4_table_index,
621                                  ip6_table_index, l2_table_index, mp->is_add);
622
623   BAD_SW_IF_INDEX_LABEL;
624
625   REPLY_MACRO (VL_API_INPUT_ACL_SET_INTERFACE_REPLY);
626 }
627
628 static void vl_api_output_acl_set_interface_t_handler
629   (vl_api_output_acl_set_interface_t * mp)
630 {
631   vlib_main_t *vm = vlib_get_main ();
632   vl_api_output_acl_set_interface_reply_t *rmp;
633   int rv;
634
635   VALIDATE_SW_IF_INDEX (mp);
636
637   u32 ip4_table_index = ntohl (mp->ip4_table_index);
638   u32 ip6_table_index = ntohl (mp->ip6_table_index);
639   u32 l2_table_index = ntohl (mp->l2_table_index);
640   u32 sw_if_index = ntohl (mp->sw_if_index);
641
642   rv = vnet_set_output_acl_intfc (vm, sw_if_index, ip4_table_index,
643                                   ip6_table_index, l2_table_index,
644                                   mp->is_add);
645
646   BAD_SW_IF_INDEX_LABEL;
647
648   REPLY_MACRO (VL_API_OUTPUT_ACL_SET_INTERFACE_REPLY);
649 }
650
651 /*
652  * classify_api_hookup
653  * Add vpe's API message handlers to the table.
654  * vlib has already mapped shared memory and
655  * added the client registration handlers.
656  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
657  */
658 #define vl_msg_name_crc_list
659 #include <vnet/vnet_all_api_h.h>
660 #undef vl_msg_name_crc_list
661
662 static void
663 setup_message_id_table (api_main_t * am)
664 {
665 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
666   foreach_vl_msg_name_crc_classify;
667 #undef _
668 }
669
670 static clib_error_t *
671 classify_api_hookup (vlib_main_t * vm)
672 {
673   api_main_t *am = &api_main;
674
675 #define _(N,n)                                                  \
676     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
677                            vl_api_##n##_t_handler,              \
678                            vl_noop_handler,                     \
679                            vl_api_##n##_t_endian,               \
680                            vl_api_##n##_t_print,                \
681                            sizeof(vl_api_##n##_t), 1);
682   foreach_vpe_api_msg;
683 #undef _
684
685   /*
686    * Set up the (msg_name, crc, message-id) table
687    */
688   setup_message_id_table (am);
689
690   return 0;
691 }
692
693 VLIB_API_INIT_FUNCTION (classify_api_hookup);
694
695 /*
696  * fd.io coding-style-patch-verification: ON
697  *
698  * Local Variables:
699  * eval: (c-set-style "gnu")
700  * End:
701  */