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