api: multiple connections per process
[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
241       >= vec_len (pcm->classify_table_index_by_sw_if_index[mp->type]))
242     return;
243
244   if (filter_sw_if_index != ~0)
245     vec_tbl =
246       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
247   else
248     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
249
250   if (vec_len (vec_tbl))
251     {
252       for (i = 0; i < vec_len (vec_tbl); i++)
253         {
254           if (vec_elt (vec_tbl, i) == ~0)
255             continue;
256
257           send_policer_classify_details (i, vec_elt (vec_tbl, i), reg,
258                                          mp->context);
259         }
260     }
261 }
262
263 static void
264 vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t * mp)
265 {
266   vl_api_registration_t *reg;
267
268   reg = vl_api_client_index_to_registration (mp->client_index);
269   if (!reg)
270     return;
271
272   vnet_classify_main_t *cm = &vnet_classify_main;
273   vnet_classify_table_t *t;
274   u32 *table_ids = 0;
275   u32 count;
276
277    /* *INDENT-OFF* */
278    pool_foreach (t, cm->tables,
279    ({
280      vec_add1 (table_ids, ntohl(t - cm->tables));
281    }));
282    /* *INDENT-ON* */
283   count = vec_len (table_ids);
284
285   vl_api_classify_table_ids_reply_t *rmp;
286   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
287   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_IDS_REPLY);
288   rmp->context = mp->context;
289   rmp->count = ntohl (count);
290   clib_memcpy (rmp->ids, table_ids, count * sizeof (u32));
291   rmp->retval = 0;
292
293   vl_api_send_msg (reg, (u8 *) rmp);
294
295   vec_free (table_ids);
296 }
297
298 static void
299   vl_api_classify_table_by_interface_t_handler
300   (vl_api_classify_table_by_interface_t * mp)
301 {
302   vl_api_classify_table_by_interface_reply_t *rmp;
303   int rv = 0;
304
305   u32 sw_if_index = ntohl (mp->sw_if_index);
306   u32 *acl = 0;
307
308   vec_validate (acl, IN_OUT_ACL_N_TABLES - 1);
309   vec_set (acl, ~0);
310
311   VALIDATE_SW_IF_INDEX (mp);
312
313   in_out_acl_main_t *am = &in_out_acl_main;
314
315   int if_idx;
316   u32 type;
317
318   for (type = 0; type < IN_OUT_ACL_N_TABLES; type++)
319     {
320       u32 *vec_tbl =
321         am->classify_table_index_by_sw_if_index[IN_OUT_ACL_INPUT_TABLE_GROUP]
322         [type];
323       if (vec_len (vec_tbl))
324         {
325           for (if_idx = 0; if_idx < vec_len (vec_tbl); if_idx++)
326             {
327               if (vec_elt (vec_tbl, if_idx) == ~0 || sw_if_index != if_idx)
328                 {
329                   continue;
330                 }
331               acl[type] = vec_elt (vec_tbl, if_idx);
332             }
333         }
334     }
335
336   BAD_SW_IF_INDEX_LABEL;
337
338    /* *INDENT-OFF* */
339    REPLY_MACRO2(VL_API_CLASSIFY_TABLE_BY_INTERFACE_REPLY,
340    ({
341      rmp->sw_if_index = ntohl(sw_if_index);
342      rmp->l2_table_id = ntohl(acl[IN_OUT_ACL_TABLE_L2]);
343      rmp->ip4_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP4]);
344      rmp->ip6_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP6]);
345    }));
346    /* *INDENT-ON* */
347   vec_free (acl);
348 }
349
350 static void
351 vl_api_classify_table_info_t_handler (vl_api_classify_table_info_t * mp)
352 {
353   vl_api_registration_t *reg;
354
355   reg = vl_api_client_index_to_registration (mp->client_index);
356   if (!reg)
357     return;
358
359   vl_api_classify_table_info_reply_t *rmp = 0;
360
361   vnet_classify_main_t *cm = &vnet_classify_main;
362   u32 table_id = ntohl (mp->table_id);
363   vnet_classify_table_t *t;
364
365    /* *INDENT-OFF* */
366    pool_foreach (t, cm->tables,
367    ({
368      if (table_id == t - cm->tables)
369        {
370          rmp = vl_msg_api_alloc_as_if_client
371            (sizeof (*rmp) + t->match_n_vectors * sizeof (u32x4));
372          rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_INFO_REPLY);
373          rmp->context = mp->context;
374          rmp->table_id = ntohl(table_id);
375          rmp->nbuckets = ntohl(t->nbuckets);
376          rmp->match_n_vectors = ntohl(t->match_n_vectors);
377          rmp->skip_n_vectors = ntohl(t->skip_n_vectors);
378          rmp->active_sessions = ntohl(t->active_elements);
379          rmp->next_table_index = ntohl(t->next_table_index);
380          rmp->miss_next_index = ntohl(t->miss_next_index);
381          rmp->mask_length = ntohl(t->match_n_vectors * sizeof (u32x4));
382          clib_memcpy(rmp->mask, t->mask, t->match_n_vectors * sizeof(u32x4));
383          rmp->retval = 0;
384          break;
385        }
386    }));
387    /* *INDENT-ON* */
388
389   if (rmp == 0)
390     {
391       rmp = vl_msg_api_alloc (sizeof (*rmp));
392       rmp->_vl_msg_id = ntohs ((VL_API_CLASSIFY_TABLE_INFO_REPLY));
393       rmp->context = mp->context;
394       rmp->retval = ntohl (VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND);
395     }
396
397   vl_api_send_msg (reg, (u8 *) rmp);
398 }
399
400 static void
401 send_classify_session_details (vl_api_registration_t * reg,
402                                u32 table_id,
403                                u32 match_length,
404                                vnet_classify_entry_t * e, u32 context)
405 {
406   vl_api_classify_session_details_t *rmp;
407
408   rmp = vl_msg_api_alloc (sizeof (*rmp));
409   clib_memset (rmp, 0, sizeof (*rmp));
410   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_SESSION_DETAILS);
411   rmp->context = context;
412   rmp->table_id = ntohl (table_id);
413   rmp->hit_next_index = ntohl (e->next_index);
414   rmp->advance = ntohl (e->advance);
415   rmp->opaque_index = ntohl (e->opaque_index);
416   rmp->match_length = ntohl (match_length);
417   clib_memcpy (rmp->match, e->key, match_length);
418
419   vl_api_send_msg (reg, (u8 *) rmp);
420 }
421
422 static void
423 vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t * mp)
424 {
425   vnet_classify_main_t *cm = &vnet_classify_main;
426   vl_api_registration_t *reg;
427
428   u32 table_id = ntohl (mp->table_id);
429   vnet_classify_table_t *t;
430
431   reg = vl_api_client_index_to_registration (mp->client_index);
432   if (!reg)
433     return;
434
435   /* *INDENT-OFF* */
436   pool_foreach (t, cm->tables,
437   ({
438     if (table_id == t - cm->tables)
439       {
440         vnet_classify_bucket_t * b;
441         vnet_classify_entry_t * v, * save_v;
442         int i, j, k;
443
444         for (i = 0; i < t->nbuckets; i++)
445           {
446             b = &t->buckets [i];
447             if (b->offset == 0)
448               continue;
449
450             save_v = vnet_classify_get_entry (t, b->offset);
451             for (j = 0; j < (1<<b->log2_pages); j++)
452               {
453                 for (k = 0; k < t->entries_per_page; k++)
454                   {
455                     v = vnet_classify_entry_at_index
456                       (t, save_v, j*t->entries_per_page + k);
457                     if (vnet_classify_entry_is_free (v))
458                       continue;
459
460                     send_classify_session_details
461                       (reg, table_id, t->match_n_vectors * sizeof (u32x4),
462                        v, mp->context);
463                   }
464               }
465           }
466         break;
467       }
468   }));
469   /* *INDENT-ON* */
470 }
471
472 static void
473   vl_api_flow_classify_set_interface_t_handler
474   (vl_api_flow_classify_set_interface_t * mp)
475 {
476   vlib_main_t *vm = vlib_get_main ();
477   vl_api_flow_classify_set_interface_reply_t *rmp;
478   int rv;
479   u32 sw_if_index, ip4_table_index, ip6_table_index;
480
481   ip4_table_index = ntohl (mp->ip4_table_index);
482   ip6_table_index = ntohl (mp->ip6_table_index);
483   sw_if_index = ntohl (mp->sw_if_index);
484
485   VALIDATE_SW_IF_INDEX (mp);
486
487   rv = vnet_set_flow_classify_intfc (vm, sw_if_index, ip4_table_index,
488                                      ip6_table_index, mp->is_add);
489
490   BAD_SW_IF_INDEX_LABEL;
491
492   REPLY_MACRO (VL_API_FLOW_CLASSIFY_SET_INTERFACE_REPLY);
493 }
494
495 static void
496 send_flow_classify_details (u32 sw_if_index,
497                             u32 table_index, vl_api_registration_t * reg,
498                             u32 context)
499 {
500   vl_api_flow_classify_details_t *mp;
501
502   mp = vl_msg_api_alloc (sizeof (*mp));
503   clib_memset (mp, 0, sizeof (*mp));
504   mp->_vl_msg_id = ntohs (VL_API_FLOW_CLASSIFY_DETAILS);
505   mp->context = context;
506   mp->sw_if_index = htonl (sw_if_index);
507   mp->table_index = htonl (table_index);
508
509   vl_api_send_msg (reg, (u8 *) mp);
510 }
511
512 static void
513 vl_api_flow_classify_dump_t_handler (vl_api_flow_classify_dump_t * mp)
514 {
515   vl_api_registration_t *reg;
516   flow_classify_main_t *pcm = &flow_classify_main;
517   u32 *vec_tbl;
518   int i;
519   u32 filter_sw_if_index;
520
521   reg = vl_api_client_index_to_registration (mp->client_index);
522   if (!reg)
523     return;
524
525   filter_sw_if_index = ntohl (mp->sw_if_index);
526   if (filter_sw_if_index
527       >= vec_len (pcm->classify_table_index_by_sw_if_index[mp->type]))
528     return;
529
530   if (filter_sw_if_index != ~0)
531     vec_tbl =
532       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
533   else
534     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
535
536   if (vec_len (vec_tbl))
537     {
538       for (i = 0; i < vec_len (vec_tbl); i++)
539         {
540           if (vec_elt (vec_tbl, i) == ~0)
541             continue;
542
543           send_flow_classify_details (i, vec_elt (vec_tbl, i), reg,
544                                       mp->context);
545         }
546     }
547 }
548
549 static void vl_api_classify_set_interface_ip_table_t_handler
550   (vl_api_classify_set_interface_ip_table_t * mp)
551 {
552   vlib_main_t *vm = vlib_get_main ();
553   vl_api_classify_set_interface_ip_table_reply_t *rmp;
554   int rv;
555
556   VALIDATE_SW_IF_INDEX (mp);
557
558   u32 table_index = ntohl (mp->table_index);
559   u32 sw_if_index = ntohl (mp->sw_if_index);
560
561   if (mp->is_ipv6)
562     rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
563   else
564     rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
565
566   BAD_SW_IF_INDEX_LABEL;
567
568   REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY);
569 }
570
571 static void vl_api_classify_set_interface_l2_tables_t_handler
572   (vl_api_classify_set_interface_l2_tables_t * mp)
573 {
574   vl_api_classify_set_interface_l2_tables_reply_t *rmp;
575   int rv;
576   u32 sw_if_index, ip4_table_index, ip6_table_index, other_table_index;
577   int enable;
578
579   ip4_table_index = ntohl (mp->ip4_table_index);
580   ip6_table_index = ntohl (mp->ip6_table_index);
581   other_table_index = ntohl (mp->other_table_index);
582   sw_if_index = ntohl (mp->sw_if_index);
583
584   VALIDATE_SW_IF_INDEX (mp);
585
586   if (mp->is_input)
587     rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
588                                             ip6_table_index,
589                                             other_table_index);
590   else
591     rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
592                                              ip6_table_index,
593                                              other_table_index);
594
595   if (rv == 0)
596     {
597       if (ip4_table_index != ~0 || ip6_table_index != ~0
598           || other_table_index != ~0)
599         enable = 1;
600       else
601         enable = 0;
602
603       if (mp->is_input)
604         vnet_l2_input_classify_enable_disable (sw_if_index, enable);
605       else
606         vnet_l2_output_classify_enable_disable (sw_if_index, enable);
607     }
608
609   BAD_SW_IF_INDEX_LABEL;
610
611   REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY);
612 }
613
614 static void vl_api_input_acl_set_interface_t_handler
615   (vl_api_input_acl_set_interface_t * mp)
616 {
617   vlib_main_t *vm = vlib_get_main ();
618   vl_api_input_acl_set_interface_reply_t *rmp;
619   int rv;
620
621   VALIDATE_SW_IF_INDEX (mp);
622
623   u32 ip4_table_index = ntohl (mp->ip4_table_index);
624   u32 ip6_table_index = ntohl (mp->ip6_table_index);
625   u32 l2_table_index = ntohl (mp->l2_table_index);
626   u32 sw_if_index = ntohl (mp->sw_if_index);
627
628   rv = vnet_set_input_acl_intfc (vm, sw_if_index, ip4_table_index,
629                                  ip6_table_index, l2_table_index, mp->is_add);
630
631   BAD_SW_IF_INDEX_LABEL;
632
633   REPLY_MACRO (VL_API_INPUT_ACL_SET_INTERFACE_REPLY);
634 }
635
636 static void vl_api_output_acl_set_interface_t_handler
637   (vl_api_output_acl_set_interface_t * mp)
638 {
639   vlib_main_t *vm = vlib_get_main ();
640   vl_api_output_acl_set_interface_reply_t *rmp;
641   int rv;
642
643   VALIDATE_SW_IF_INDEX (mp);
644
645   u32 ip4_table_index = ntohl (mp->ip4_table_index);
646   u32 ip6_table_index = ntohl (mp->ip6_table_index);
647   u32 l2_table_index = ntohl (mp->l2_table_index);
648   u32 sw_if_index = ntohl (mp->sw_if_index);
649
650   rv = vnet_set_output_acl_intfc (vm, sw_if_index, ip4_table_index,
651                                   ip6_table_index, l2_table_index,
652                                   mp->is_add);
653
654   BAD_SW_IF_INDEX_LABEL;
655
656   REPLY_MACRO (VL_API_OUTPUT_ACL_SET_INTERFACE_REPLY);
657 }
658
659 /*
660  * classify_api_hookup
661  * Add vpe's API message handlers to the table.
662  * vlib has already mapped shared memory and
663  * added the client registration handlers.
664  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
665  */
666 #define vl_msg_name_crc_list
667 #include <vnet/vnet_all_api_h.h>
668 #undef vl_msg_name_crc_list
669
670 static void
671 setup_message_id_table (api_main_t * am)
672 {
673 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
674   foreach_vl_msg_name_crc_classify;
675 #undef _
676 }
677
678 static clib_error_t *
679 classify_api_hookup (vlib_main_t * vm)
680 {
681   api_main_t *am = vlibapi_get_main ();
682
683 #define _(N,n)                                                  \
684     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
685                            vl_api_##n##_t_handler,              \
686                            vl_noop_handler,                     \
687                            vl_api_##n##_t_endian,               \
688                            vl_api_##n##_t_print,                \
689                            sizeof(vl_api_##n##_t), 1);
690   foreach_vpe_api_msg;
691 #undef _
692
693   /*
694    * Set up the (msg_name, crc, message-id) table
695    */
696   setup_message_id_table (am);
697
698   return 0;
699 }
700
701 VLIB_API_INIT_FUNCTION (classify_api_hookup);
702
703 /*
704  * fd.io coding-style-patch-verification: ON
705  *
706  * Local Variables:
707  * eval: (c-set-style "gnu")
708  * End:
709  */