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