classify: add pcap/trace classfier mgmt API calls
[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 _(CLASSIFY_PCAP_LOOKUP_TABLE, classify_pcap_lookup_table)               \
68 _(CLASSIFY_PCAP_SET_TABLE, classify_pcap_set_table)                     \
69 _(CLASSIFY_PCAP_GET_TABLES, classify_pcap_get_tables)                   \
70 _(CLASSIFY_TRACE_LOOKUP_TABLE, classify_trace_lookup_table)             \
71 _(CLASSIFY_TRACE_SET_TABLE, classify_trace_set_table)                   \
72 _(CLASSIFY_TRACE_GET_TABLES, classify_trace_get_tables)                 \
73
74
75 #define foreach_classify_add_del_table_field    \
76 _(table_index)                                  \
77 _(nbuckets)                                     \
78 _(memory_size)                                  \
79 _(skip_n_vectors)                               \
80 _(match_n_vectors)                              \
81 _(next_table_index)                             \
82 _(miss_next_index)                              \
83 _(mask_len)
84
85
86 static void vl_api_classify_pcap_lookup_table_t_handler
87   (vl_api_classify_pcap_lookup_table_t * mp)
88 {
89   vnet_classify_main_t *cm = &vnet_classify_main;
90   vl_api_registration_t *reg;
91   vl_api_classify_pcap_lookup_table_reply_t *rmp;
92   int rv = 0;
93   u32 table_index = ~0;
94
95   reg = vl_api_client_index_to_registration (mp->client_index);
96   if (!reg)
97     return;
98
99   u32 n_skip = ntohl (mp->skip_n_vectors);
100   u32 n_match = ntohl (mp->match_n_vectors);
101   u32 mask_len = ntohl (mp->mask_len);
102   u32 sw_if_index = ntohl (mp->sw_if_index);
103
104   if (n_skip > 5
105       || 0 <= n_match || n_match > 5
106       || mask_len != n_match * sizeof (u32x4)
107       || sw_if_index == ~0
108       || sw_if_index >= vec_len (cm->classify_table_index_by_sw_if_index))
109     {
110       rv = VNET_API_ERROR_INVALID_VALUE;
111       goto out;
112     }
113
114   u32 table_chain;
115   table_chain = classify_get_pcap_chain (cm, sw_if_index);
116
117   u8 *mask_vec = 0;
118   vec_validate (mask_vec, mask_len - 1);
119   clib_memcpy (mask_vec, mp->mask, mask_len);
120
121   if (table_chain != ~0)
122     table_index = classify_lookup_chain (table_chain,
123                                          mask_vec, n_skip, n_match);
124
125   vec_free (mask_vec);
126
127 out:
128   rmp = vl_msg_api_alloc (sizeof (*rmp));
129   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_PCAP_LOOKUP_TABLE_REPLY);
130   rmp->context = mp->context;
131   rmp->retval = ntohl (rv);
132   rmp->table_index = htonl (table_index);
133
134   vl_api_send_msg (reg, (u8 *) rmp);
135 }
136
137 static void vl_api_classify_pcap_set_table_t_handler
138   (vl_api_classify_pcap_set_table_t * mp)
139 {
140   vnet_classify_main_t *cm = &vnet_classify_main;
141   vl_api_classify_pcap_set_table_reply_t *rmp;
142   vl_api_registration_t *reg;
143   int rv = 0;
144
145   reg = vl_api_client_index_to_registration (mp->client_index);
146   if (!reg)
147     return;
148
149   u32 table_index = ntohl (mp->table_index);
150   u32 sw_if_index = ntohl (mp->sw_if_index);
151
152   if (sw_if_index == ~0
153       || sw_if_index >= vec_len (cm->classify_table_index_by_sw_if_index)
154       || (table_index != ~0 && pool_is_free_index (cm->tables, table_index)))
155     {
156       rv = VNET_API_ERROR_INVALID_VALUE;
157       goto out;
158     }
159
160   /*
161    * Maybe reorder tables such that masks are most-specify to least-specific.
162    */
163   if (table_index != ~0 && mp->sort_masks)
164     table_index = classify_sort_table_chain (cm, table_index);
165
166   classify_set_pcap_chain (cm, sw_if_index, table_index);
167
168 out:
169   rmp = vl_msg_api_alloc (sizeof (*rmp));
170   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_PCAP_SET_TABLE_REPLY);
171   rmp->context = mp->context;
172   rmp->retval = ntohl (rv);
173   rmp->table_index = htonl (table_index);
174
175   vl_api_send_msg (reg, (u8 *) rmp);
176 }
177
178 static void vl_api_classify_pcap_get_tables_t_handler
179   (vl_api_classify_pcap_get_tables_t * mp)
180 {
181   vnet_classify_main_t *cm = &vnet_classify_main;
182   vl_api_classify_pcap_get_tables_reply_t *rmp;
183   vl_api_registration_t *reg;
184   int rv = 0;
185   u32 *tables = 0;
186   u32 count;
187
188   reg = vl_api_client_index_to_registration (mp->client_index);
189   if (!reg)
190     return;
191
192   u32 sw_if_index = ntohl (mp->sw_if_index);
193   if (sw_if_index == ~0
194       || sw_if_index >= vec_len (cm->classify_table_index_by_sw_if_index))
195     {
196       rv = VNET_API_ERROR_INVALID_VALUE;
197       goto out;
198     }
199
200   u32 table_index = classify_get_pcap_chain (cm, sw_if_index);
201   if (table_index == ~0)
202     goto out;
203
204   /*
205    * Form a vector of all classifier tables in this chain.
206    */
207   vnet_classify_table_t *t;
208   u32 i;
209
210   for (i = table_index; i != ~0; i = t->next_table_index)
211     {
212       vec_add1 (tables, i);
213       t = pool_elt_at_index (cm->tables, i);
214     }
215
216 out:
217   count = vec_len (tables);
218   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
219   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_PCAP_GET_TABLES_REPLY);
220   rmp->context = mp->context;
221   rmp->retval = ntohl (rv);
222   rmp->count = htonl (count);
223
224   for (i = 0; i < count; ++i)
225     {
226       rmp->indices[i] = htonl (tables[i]);
227     }
228
229   vec_free (tables);
230
231   vl_api_send_msg (reg, (u8 *) rmp);
232 }
233
234
235 static void vl_api_classify_trace_lookup_table_t_handler
236   (vl_api_classify_trace_lookup_table_t * mp)
237 {
238   vl_api_classify_trace_lookup_table_reply_t *rmp;
239   vl_api_registration_t *reg;
240   int rv = 0;
241   u32 table_index = ~0;
242
243   reg = vl_api_client_index_to_registration (mp->client_index);
244   if (!reg)
245     return;
246
247   u32 n_skip = ntohl (mp->skip_n_vectors);
248   u32 n_match = ntohl (mp->match_n_vectors);
249   u32 mask_len = ntohl (mp->mask_len);
250   if (n_skip > 5
251       || n_match == 0 || n_match > 5 || mask_len != n_match * sizeof (u32x4))
252     {
253       rv = VNET_API_ERROR_INVALID_VALUE;
254       goto out;
255     }
256
257   u32 table_chain;
258   table_chain = classify_get_trace_chain ();
259
260   u8 *mask_vec = 0;
261   vec_validate (mask_vec, mask_len - 1);
262   clib_memcpy (mask_vec, mp->mask, mask_len);
263
264   if (table_chain != ~0)
265     table_index = classify_lookup_chain (table_chain,
266                                          mask_vec, n_skip, n_match);
267   vec_free (mask_vec);
268
269 out:
270   rmp = vl_msg_api_alloc (sizeof (*rmp));
271   rmp->_vl_msg_id = ntohs ((VL_API_CLASSIFY_TRACE_LOOKUP_TABLE_REPLY));
272   rmp->context = mp->context;
273   rmp->retval = ntohl (rv);
274   rmp->table_index = htonl (table_index);
275
276   vl_api_send_msg (reg, (u8 *) rmp);
277 }
278
279 static void vl_api_classify_trace_set_table_t_handler
280   (vl_api_classify_trace_set_table_t * mp)
281 {
282   vnet_classify_main_t *cm = &vnet_classify_main;
283   vl_api_classify_trace_set_table_reply_t *rmp;
284   vl_api_registration_t *reg;
285   int rv = 0;
286
287   reg = vl_api_client_index_to_registration (mp->client_index);
288   if (!reg)
289     return;
290
291   u32 table_index = ntohl (mp->table_index);
292   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
293     {
294       rv = VNET_API_ERROR_INVALID_VALUE;
295       goto out;
296     }
297
298   /*
299    * Maybe reorder tables such that masks are most-specific to least-specific.
300    */
301   if (table_index != ~0 && mp->sort_masks)
302     table_index = classify_sort_table_chain (cm, table_index);
303
304   classify_set_trace_chain (cm, table_index);
305
306 out:
307   rmp = vl_msg_api_alloc (sizeof (*rmp));
308   rmp->_vl_msg_id = ntohs ((VL_API_CLASSIFY_TRACE_SET_TABLE_REPLY));
309   rmp->context = mp->context;
310   rmp->retval = ntohl (rv);
311   rmp->table_index = htonl (table_index);
312
313   vl_api_send_msg (reg, (u8 *) rmp);
314 }
315
316 static void vl_api_classify_trace_get_tables_t_handler
317   (vl_api_classify_trace_get_tables_t * mp)
318 {
319   vnet_classify_main_t *cm = &vnet_classify_main;
320   vl_api_classify_trace_get_tables_reply_t *rmp;
321   vl_api_registration_t *reg;
322   int rv = 0;
323   u32 *tables = 0;
324   u32 count;
325
326   reg = vl_api_client_index_to_registration (mp->client_index);
327   if (!reg)
328     return;
329
330   u32 table_index = classify_get_trace_chain ();
331   if (table_index == ~0)
332     goto out;
333
334   /*
335    * Form a vector of all classifier tables in this chain.
336    */
337   vnet_classify_table_t *t;
338   u32 i;
339
340   for (i = table_index; i != ~0; i = t->next_table_index)
341     {
342       vec_add1 (tables, i);
343       t = pool_elt_at_index (cm->tables, i);
344     }
345
346 out:
347   count = vec_len (tables);
348   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
349   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TRACE_GET_TABLES_REPLY);
350   rmp->context = mp->context;
351   rmp->retval = ntohl (rv);
352   rmp->count = htonl (count);
353
354   for (i = 0; i < count; ++i)
355     {
356       rmp->indices[i] = htonl (tables[i]);
357     }
358
359   vec_free (tables);
360
361   vl_api_send_msg (reg, (u8 *) rmp);
362 }
363
364
365 static void vl_api_classify_add_del_table_t_handler
366   (vl_api_classify_add_del_table_t * mp)
367 {
368   vl_api_classify_add_del_table_reply_t *rmp;
369   vnet_classify_main_t *cm = &vnet_classify_main;
370   vnet_classify_table_t *t;
371   int rv;
372
373 #define _(a) u32 a;
374   foreach_classify_add_del_table_field;
375 #undef _
376
377 #define _(a) a = ntohl(mp->a);
378   foreach_classify_add_del_table_field;
379 #undef _
380
381   if (mask_len != match_n_vectors * sizeof (u32x4))
382     {
383       rv = VNET_API_ERROR_INVALID_VALUE;
384       goto out;
385     }
386
387   /* The underlying API fails silently, on purpose, so check here */
388   if (mp->is_add == 0)          /* delete */
389     {
390       if (pool_is_free_index (cm->tables, table_index))
391         {
392           rv = VNET_API_ERROR_NO_SUCH_TABLE;
393           goto out;
394         }
395     }
396   else                          /* add or update */
397     {
398       if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
399         table_index = ~0;
400     }
401
402   u8 current_data_flag = mp->current_data_flag;
403   i16 current_data_offset = clib_net_to_host_i16 (mp->current_data_offset);
404
405   rv = vnet_classify_add_del_table
406     (cm, mp->mask, nbuckets, memory_size,
407      skip_n_vectors, match_n_vectors,
408      next_table_index, miss_next_index, &table_index,
409      current_data_flag, current_data_offset, mp->is_add, mp->del_chain);
410
411 out:
412   /* *INDENT-OFF* */
413   REPLY_MACRO2(VL_API_CLASSIFY_ADD_DEL_TABLE_REPLY,
414   ({
415     if (rv == 0 && mp->is_add)
416       {
417         t = pool_elt_at_index (cm->tables, table_index);
418         rmp->skip_n_vectors = htonl(t->skip_n_vectors);
419         rmp->match_n_vectors = htonl(t->match_n_vectors);
420         rmp->new_table_index = htonl(table_index);
421       }
422     else
423       {
424         rmp->skip_n_vectors = ~0;
425         rmp->match_n_vectors = ~0;
426         rmp->new_table_index = ~0;
427       }
428   }));
429   /* *INDENT-ON* */
430 }
431
432 static void vl_api_classify_add_del_session_t_handler
433   (vl_api_classify_add_del_session_t * mp)
434 {
435   vnet_classify_main_t *cm = &vnet_classify_main;
436   vl_api_classify_add_del_session_reply_t *rmp;
437   int rv;
438   u32 table_index, hit_next_index, opaque_index, metadata, match_len;
439   i32 advance;
440   u8 action;
441   vnet_classify_table_t *t;
442
443   table_index = ntohl (mp->table_index);
444   hit_next_index = ntohl (mp->hit_next_index);
445   opaque_index = ntohl (mp->opaque_index);
446   advance = ntohl (mp->advance);
447   action = mp->action;
448   metadata = ntohl (mp->metadata);
449   match_len = ntohl (mp->match_len);
450
451   if (pool_is_free_index (cm->tables, table_index))
452     {
453       rv = VNET_API_ERROR_NO_SUCH_TABLE;
454       goto out;
455     }
456
457   t = pool_elt_at_index (cm->tables, table_index);
458
459   if (match_len != (t->skip_n_vectors + t->match_n_vectors) * sizeof (u32x4))
460     {
461       rv = VNET_API_ERROR_INVALID_VALUE;
462       goto out;
463     }
464
465   rv = vnet_classify_add_del_session
466     (cm, table_index, mp->match, hit_next_index, opaque_index,
467      advance, action, metadata, mp->is_add);
468
469 out:
470   REPLY_MACRO (VL_API_CLASSIFY_ADD_DEL_SESSION_REPLY);
471 }
472
473 static void
474   vl_api_policer_classify_set_interface_t_handler
475   (vl_api_policer_classify_set_interface_t * mp)
476 {
477   vlib_main_t *vm = vlib_get_main ();
478   vl_api_policer_classify_set_interface_reply_t *rmp;
479   int rv;
480   u32 sw_if_index, ip4_table_index, ip6_table_index, l2_table_index;
481
482   ip4_table_index = ntohl (mp->ip4_table_index);
483   ip6_table_index = ntohl (mp->ip6_table_index);
484   l2_table_index = ntohl (mp->l2_table_index);
485   sw_if_index = ntohl (mp->sw_if_index);
486
487   VALIDATE_SW_IF_INDEX (mp);
488
489   rv = vnet_set_policer_classify_intfc (vm, sw_if_index, ip4_table_index,
490                                         ip6_table_index, l2_table_index,
491                                         mp->is_add);
492
493   BAD_SW_IF_INDEX_LABEL;
494
495   REPLY_MACRO (VL_API_POLICER_CLASSIFY_SET_INTERFACE_REPLY);
496 }
497
498 static void
499 send_policer_classify_details (u32 sw_if_index,
500                                u32 table_index, vl_api_registration_t * reg,
501                                u32 context)
502 {
503   vl_api_policer_classify_details_t *mp;
504
505   mp = vl_msg_api_alloc (sizeof (*mp));
506   clib_memset (mp, 0, sizeof (*mp));
507   mp->_vl_msg_id = ntohs (VL_API_POLICER_CLASSIFY_DETAILS);
508   mp->context = context;
509   mp->sw_if_index = htonl (sw_if_index);
510   mp->table_index = htonl (table_index);
511
512   vl_api_send_msg (reg, (u8 *) mp);
513 }
514
515 static void
516 vl_api_policer_classify_dump_t_handler (vl_api_policer_classify_dump_t * mp)
517 {
518   vl_api_registration_t *reg;
519   policer_classify_main_t *pcm = &policer_classify_main;
520   u32 *vec_tbl;
521   int i;
522   u32 filter_sw_if_index;
523
524   reg = vl_api_client_index_to_registration (mp->client_index);
525   if (!reg)
526     return;
527
528   filter_sw_if_index = ntohl (mp->sw_if_index);
529   if (filter_sw_if_index
530       >= vec_len (pcm->classify_table_index_by_sw_if_index[mp->type]))
531     return;
532
533   if (filter_sw_if_index != ~0)
534     vec_tbl =
535       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
536   else
537     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
538
539   if (vec_len (vec_tbl))
540     {
541       for (i = 0; i < vec_len (vec_tbl); i++)
542         {
543           if (vec_elt (vec_tbl, i) == ~0)
544             continue;
545
546           send_policer_classify_details (i, vec_elt (vec_tbl, i), reg,
547                                          mp->context);
548         }
549     }
550 }
551
552 static void
553 vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t * mp)
554 {
555   vl_api_registration_t *reg;
556
557   reg = vl_api_client_index_to_registration (mp->client_index);
558   if (!reg)
559     return;
560
561   vnet_classify_main_t *cm = &vnet_classify_main;
562   vnet_classify_table_t *t;
563   u32 *table_ids = 0;
564   u32 count;
565
566    /* *INDENT-OFF* */
567    pool_foreach (t, cm->tables)
568     {
569      vec_add1 (table_ids, ntohl(t - cm->tables));
570    }
571    /* *INDENT-ON* */
572   count = vec_len (table_ids);
573
574   vl_api_classify_table_ids_reply_t *rmp;
575   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
576   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_IDS_REPLY);
577   rmp->context = mp->context;
578   rmp->count = ntohl (count);
579   clib_memcpy (rmp->ids, table_ids, count * sizeof (u32));
580   rmp->retval = 0;
581
582   vl_api_send_msg (reg, (u8 *) rmp);
583
584   vec_free (table_ids);
585 }
586
587 static void
588   vl_api_classify_table_by_interface_t_handler
589   (vl_api_classify_table_by_interface_t * mp)
590 {
591   vl_api_classify_table_by_interface_reply_t *rmp;
592   int rv = 0;
593
594   u32 sw_if_index = ntohl (mp->sw_if_index);
595   u32 *acl = 0;
596
597   vec_validate (acl, IN_OUT_ACL_N_TABLES - 1);
598   vec_set (acl, ~0);
599
600   VALIDATE_SW_IF_INDEX (mp);
601
602   in_out_acl_main_t *am = &in_out_acl_main;
603
604   int if_idx;
605   u32 type;
606
607   for (type = 0; type < IN_OUT_ACL_N_TABLES; type++)
608     {
609       u32 *vec_tbl =
610         am->classify_table_index_by_sw_if_index[IN_OUT_ACL_INPUT_TABLE_GROUP]
611         [type];
612       if (vec_len (vec_tbl))
613         {
614           for (if_idx = 0; if_idx < vec_len (vec_tbl); if_idx++)
615             {
616               if (vec_elt (vec_tbl, if_idx) == ~0 || sw_if_index != if_idx)
617                 {
618                   continue;
619                 }
620               acl[type] = vec_elt (vec_tbl, if_idx);
621             }
622         }
623     }
624
625   BAD_SW_IF_INDEX_LABEL;
626
627    /* *INDENT-OFF* */
628    REPLY_MACRO2(VL_API_CLASSIFY_TABLE_BY_INTERFACE_REPLY,
629    ({
630      rmp->sw_if_index = ntohl(sw_if_index);
631      rmp->l2_table_id = ntohl(acl[IN_OUT_ACL_TABLE_L2]);
632      rmp->ip4_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP4]);
633      rmp->ip6_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP6]);
634    }));
635    /* *INDENT-ON* */
636   vec_free (acl);
637 }
638
639 static void
640 vl_api_classify_table_info_t_handler (vl_api_classify_table_info_t * mp)
641 {
642   vl_api_registration_t *reg;
643
644   reg = vl_api_client_index_to_registration (mp->client_index);
645   if (!reg)
646     return;
647
648   vl_api_classify_table_info_reply_t *rmp = 0;
649
650   vnet_classify_main_t *cm = &vnet_classify_main;
651   u32 table_id = ntohl (mp->table_id);
652   vnet_classify_table_t *t;
653
654    /* *INDENT-OFF* */
655    pool_foreach (t, cm->tables)
656     {
657      if (table_id == t - cm->tables)
658        {
659          rmp = vl_msg_api_alloc_as_if_client
660            (sizeof (*rmp) + t->match_n_vectors * sizeof (u32x4));
661          rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_INFO_REPLY);
662          rmp->context = mp->context;
663          rmp->table_id = ntohl(table_id);
664          rmp->nbuckets = ntohl(t->nbuckets);
665          rmp->match_n_vectors = ntohl(t->match_n_vectors);
666          rmp->skip_n_vectors = ntohl(t->skip_n_vectors);
667          rmp->active_sessions = ntohl(t->active_elements);
668          rmp->next_table_index = ntohl(t->next_table_index);
669          rmp->miss_next_index = ntohl(t->miss_next_index);
670          rmp->mask_length = ntohl(t->match_n_vectors * sizeof (u32x4));
671          clib_memcpy(rmp->mask, t->mask, t->match_n_vectors * sizeof(u32x4));
672          rmp->retval = 0;
673          break;
674        }
675    }
676    /* *INDENT-ON* */
677
678   if (rmp == 0)
679     {
680       rmp = vl_msg_api_alloc (sizeof (*rmp));
681       rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_TABLE_INFO_REPLY);
682       rmp->context = mp->context;
683       rmp->retval = ntohl (VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND);
684     }
685
686   vl_api_send_msg (reg, (u8 *) rmp);
687 }
688
689 static void
690 send_classify_session_details (vl_api_registration_t * reg,
691                                u32 table_id,
692                                u32 match_length,
693                                vnet_classify_entry_t * e, u32 context)
694 {
695   vl_api_classify_session_details_t *rmp;
696
697   rmp = vl_msg_api_alloc (sizeof (*rmp));
698   clib_memset (rmp, 0, sizeof (*rmp));
699   rmp->_vl_msg_id = ntohs (VL_API_CLASSIFY_SESSION_DETAILS);
700   rmp->context = context;
701   rmp->table_id = ntohl (table_id);
702   rmp->hit_next_index = ntohl (e->next_index);
703   rmp->advance = ntohl (e->advance);
704   rmp->opaque_index = ntohl (e->opaque_index);
705   rmp->match_length = ntohl (match_length);
706   clib_memcpy (rmp->match, e->key, match_length);
707
708   vl_api_send_msg (reg, (u8 *) rmp);
709 }
710
711 static void
712 vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t * mp)
713 {
714   vnet_classify_main_t *cm = &vnet_classify_main;
715   vl_api_registration_t *reg;
716
717   u32 table_id = ntohl (mp->table_id);
718   vnet_classify_table_t *t;
719
720   reg = vl_api_client_index_to_registration (mp->client_index);
721   if (!reg)
722     return;
723
724   /* *INDENT-OFF* */
725   pool_foreach (t, cm->tables)
726    {
727     if (table_id == t - cm->tables)
728       {
729         vnet_classify_bucket_t * b;
730         vnet_classify_entry_t * v, * save_v;
731         int i, j, k;
732
733         for (i = 0; i < t->nbuckets; i++)
734           {
735             b = &t->buckets [i];
736             if (b->offset == 0)
737               continue;
738
739             save_v = vnet_classify_get_entry (t, b->offset);
740             for (j = 0; j < (1<<b->log2_pages); j++)
741               {
742                 for (k = 0; k < t->entries_per_page; k++)
743                   {
744                     v = vnet_classify_entry_at_index
745                       (t, save_v, j*t->entries_per_page + k);
746                     if (vnet_classify_entry_is_free (v))
747                       continue;
748
749                     send_classify_session_details
750                       (reg, table_id, t->match_n_vectors * sizeof (u32x4),
751                        v, mp->context);
752                   }
753               }
754           }
755         break;
756       }
757   }
758   /* *INDENT-ON* */
759 }
760
761 static void
762   vl_api_flow_classify_set_interface_t_handler
763   (vl_api_flow_classify_set_interface_t * mp)
764 {
765   vlib_main_t *vm = vlib_get_main ();
766   vl_api_flow_classify_set_interface_reply_t *rmp;
767   int rv;
768   u32 sw_if_index, ip4_table_index, ip6_table_index;
769
770   ip4_table_index = ntohl (mp->ip4_table_index);
771   ip6_table_index = ntohl (mp->ip6_table_index);
772   sw_if_index = ntohl (mp->sw_if_index);
773
774   VALIDATE_SW_IF_INDEX (mp);
775
776   rv = vnet_set_flow_classify_intfc (vm, sw_if_index, ip4_table_index,
777                                      ip6_table_index, mp->is_add);
778
779   BAD_SW_IF_INDEX_LABEL;
780
781   REPLY_MACRO (VL_API_FLOW_CLASSIFY_SET_INTERFACE_REPLY);
782 }
783
784 static void
785 send_flow_classify_details (u32 sw_if_index,
786                             u32 table_index, vl_api_registration_t * reg,
787                             u32 context)
788 {
789   vl_api_flow_classify_details_t *mp;
790
791   mp = vl_msg_api_alloc (sizeof (*mp));
792   clib_memset (mp, 0, sizeof (*mp));
793   mp->_vl_msg_id = ntohs (VL_API_FLOW_CLASSIFY_DETAILS);
794   mp->context = context;
795   mp->sw_if_index = htonl (sw_if_index);
796   mp->table_index = htonl (table_index);
797
798   vl_api_send_msg (reg, (u8 *) mp);
799 }
800
801 static void
802 vl_api_flow_classify_dump_t_handler (vl_api_flow_classify_dump_t * mp)
803 {
804   vl_api_registration_t *reg;
805   flow_classify_main_t *pcm = &flow_classify_main;
806   u32 *vec_tbl;
807   int i;
808   u32 filter_sw_if_index;
809
810   reg = vl_api_client_index_to_registration (mp->client_index);
811   if (!reg)
812     return;
813
814   filter_sw_if_index = ntohl (mp->sw_if_index);
815   if (filter_sw_if_index
816       >= vec_len (pcm->classify_table_index_by_sw_if_index[mp->type]))
817     return;
818
819   if (filter_sw_if_index != ~0)
820     vec_tbl =
821       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
822   else
823     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
824
825   if (vec_len (vec_tbl))
826     {
827       for (i = 0; i < vec_len (vec_tbl); i++)
828         {
829           if (vec_elt (vec_tbl, i) == ~0)
830             continue;
831
832           send_flow_classify_details (i, vec_elt (vec_tbl, i), reg,
833                                       mp->context);
834         }
835     }
836 }
837
838 static void vl_api_classify_set_interface_ip_table_t_handler
839   (vl_api_classify_set_interface_ip_table_t * mp)
840 {
841   vlib_main_t *vm = vlib_get_main ();
842   vl_api_classify_set_interface_ip_table_reply_t *rmp;
843   int rv;
844
845   VALIDATE_SW_IF_INDEX (mp);
846
847   u32 table_index = ntohl (mp->table_index);
848   u32 sw_if_index = ntohl (mp->sw_if_index);
849
850   if (mp->is_ipv6)
851     rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
852   else
853     rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
854
855   BAD_SW_IF_INDEX_LABEL;
856
857   REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY);
858 }
859
860 static void vl_api_classify_set_interface_l2_tables_t_handler
861   (vl_api_classify_set_interface_l2_tables_t * mp)
862 {
863   vl_api_classify_set_interface_l2_tables_reply_t *rmp;
864   int rv;
865   u32 sw_if_index, ip4_table_index, ip6_table_index, other_table_index;
866   int enable;
867
868   ip4_table_index = ntohl (mp->ip4_table_index);
869   ip6_table_index = ntohl (mp->ip6_table_index);
870   other_table_index = ntohl (mp->other_table_index);
871   sw_if_index = ntohl (mp->sw_if_index);
872
873   VALIDATE_SW_IF_INDEX (mp);
874
875   if (mp->is_input)
876     rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
877                                             ip6_table_index,
878                                             other_table_index);
879   else
880     rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
881                                              ip6_table_index,
882                                              other_table_index);
883
884   if (rv == 0)
885     {
886       if (ip4_table_index != ~0 || ip6_table_index != ~0
887           || other_table_index != ~0)
888         enable = 1;
889       else
890         enable = 0;
891
892       if (mp->is_input)
893         vnet_l2_input_classify_enable_disable (sw_if_index, enable);
894       else
895         vnet_l2_output_classify_enable_disable (sw_if_index, enable);
896     }
897
898   BAD_SW_IF_INDEX_LABEL;
899
900   REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY);
901 }
902
903 static void vl_api_input_acl_set_interface_t_handler
904   (vl_api_input_acl_set_interface_t * mp)
905 {
906   vlib_main_t *vm = vlib_get_main ();
907   vl_api_input_acl_set_interface_reply_t *rmp;
908   int rv;
909
910   VALIDATE_SW_IF_INDEX (mp);
911
912   u32 ip4_table_index = ntohl (mp->ip4_table_index);
913   u32 ip6_table_index = ntohl (mp->ip6_table_index);
914   u32 l2_table_index = ntohl (mp->l2_table_index);
915   u32 sw_if_index = ntohl (mp->sw_if_index);
916
917   rv = vnet_set_input_acl_intfc (vm, sw_if_index, ip4_table_index,
918                                  ip6_table_index, l2_table_index, mp->is_add);
919
920   BAD_SW_IF_INDEX_LABEL;
921
922   REPLY_MACRO (VL_API_INPUT_ACL_SET_INTERFACE_REPLY);
923 }
924
925 static void vl_api_output_acl_set_interface_t_handler
926   (vl_api_output_acl_set_interface_t * mp)
927 {
928   vlib_main_t *vm = vlib_get_main ();
929   vl_api_output_acl_set_interface_reply_t *rmp;
930   int rv;
931
932   VALIDATE_SW_IF_INDEX (mp);
933
934   u32 ip4_table_index = ntohl (mp->ip4_table_index);
935   u32 ip6_table_index = ntohl (mp->ip6_table_index);
936   u32 l2_table_index = ntohl (mp->l2_table_index);
937   u32 sw_if_index = ntohl (mp->sw_if_index);
938
939   rv = vnet_set_output_acl_intfc (vm, sw_if_index, ip4_table_index,
940                                   ip6_table_index, l2_table_index,
941                                   mp->is_add);
942
943   BAD_SW_IF_INDEX_LABEL;
944
945   REPLY_MACRO (VL_API_OUTPUT_ACL_SET_INTERFACE_REPLY);
946 }
947
948 /*
949  * classify_api_hookup
950  * Add vpe's API message handlers to the table.
951  * vlib has already mapped shared memory and
952  * added the client registration handlers.
953  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
954  */
955 #define vl_msg_name_crc_list
956 #include <vnet/vnet_all_api_h.h>
957 #undef vl_msg_name_crc_list
958
959 static void
960 setup_message_id_table (api_main_t * am)
961 {
962 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
963   foreach_vl_msg_name_crc_classify;
964 #undef _
965 }
966
967 static clib_error_t *
968 classify_api_hookup (vlib_main_t * vm)
969 {
970   api_main_t *am = vlibapi_get_main ();
971
972 #define _(N,n)                                                  \
973     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
974                            vl_api_##n##_t_handler,              \
975                            vl_noop_handler,                     \
976                            vl_api_##n##_t_endian,               \
977                            vl_api_##n##_t_print,                \
978                            sizeof(vl_api_##n##_t), 1);
979   foreach_vpe_api_msg;
980 #undef _
981
982   /*
983    * Set up the (msg_name, crc, message-id) table
984    */
985   setup_message_id_table (am);
986
987   return 0;
988 }
989
990 VLIB_API_INIT_FUNCTION (classify_api_hookup);
991
992 /*
993  * fd.io coding-style-patch-verification: ON
994  *
995  * Local Variables:
996  * eval: (c-set-style "gnu")
997  * End:
998  */