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