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