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