session: remove ipv6 lookup threading assert
[vpp.git] / src / vnet / classify / classify_api.c
1 /*
2  *------------------------------------------------------------------
3  * classify_api.c - classify api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25
26 #include <vnet/classify/vnet_classify.h>
27 #include <vnet/classify/in_out_acl.h>
28 #include <vnet/classify/policer_classify.h>
29 #include <vnet/classify/flow_classify.h>
30 #include <vnet/l2/l2_classify.h>
31 #include <vnet/ip/ip6.h>
32 #include <vnet/ip/ip4.h>
33
34 #include <classify/classify.api_enum.h>
35 #include <classify/classify.api_types.h>
36
37 #define REPLY_MSG_ID_BASE msg_id_base
38 #include <vlibapi/api_helper_macros.h>
39
40 static u16 msg_id_base;
41
42 #define foreach_classify_add_del_table_field    \
43 _(table_index)                                  \
44 _(nbuckets)                                     \
45 _(memory_size)                                  \
46 _(skip_n_vectors)                               \
47 _(match_n_vectors)                              \
48 _(next_table_index)                             \
49 _(miss_next_index)                              \
50 _(mask_len)
51
52
53 static void vl_api_classify_pcap_lookup_table_t_handler
54   (vl_api_classify_pcap_lookup_table_t * mp)
55 {
56   vnet_classify_main_t *cm = &vnet_classify_main;
57   vl_api_registration_t *reg;
58   vl_api_classify_pcap_lookup_table_reply_t *rmp;
59   int rv = 0;
60   u32 table_index = ~0;
61
62   reg = vl_api_client_index_to_registration (mp->client_index);
63   if (!reg)
64     return;
65
66   u32 n_skip = ntohl (mp->skip_n_vectors);
67   u32 n_match = ntohl (mp->match_n_vectors);
68   u32 mask_len = ntohl (mp->mask_len);
69   u32 sw_if_index = ntohl (mp->sw_if_index);
70
71   if (n_skip > 5 || n_match == 0 || n_match > 5 ||
72       mask_len != n_match * sizeof (u32x4) || sw_if_index == ~0 ||
73       sw_if_index >= vec_len (cm->classify_table_index_by_sw_if_index))
74     {
75       rv = VNET_API_ERROR_INVALID_VALUE;
76       goto out;
77     }
78
79   u32 table_chain;
80   table_chain = classify_get_pcap_chain (cm, sw_if_index);
81
82   u8 *mask_vec = 0;
83   vec_validate (mask_vec, mask_len - 1);
84   clib_memcpy (mask_vec, mp->mask, mask_len);
85
86   if (table_chain != ~0)
87     table_index = classify_lookup_chain (table_chain,
88                                          mask_vec, n_skip, n_match);
89
90   vec_free (mask_vec);
91
92 out:
93   rmp = vl_msg_api_alloc (sizeof (*rmp));
94   rmp->_vl_msg_id =
95     ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_PCAP_LOOKUP_TABLE_REPLY);
96   rmp->context = mp->context;
97   rmp->retval = ntohl (rv);
98   rmp->table_index = htonl (table_index);
99
100   vl_api_send_msg (reg, (u8 *) rmp);
101 }
102
103 static void vl_api_classify_pcap_set_table_t_handler
104   (vl_api_classify_pcap_set_table_t * mp)
105 {
106   vnet_classify_main_t *cm = &vnet_classify_main;
107   vl_api_classify_pcap_set_table_reply_t *rmp;
108   vl_api_registration_t *reg;
109   int rv = 0;
110
111   reg = vl_api_client_index_to_registration (mp->client_index);
112   if (!reg)
113     return;
114
115   u32 table_index = ntohl (mp->table_index);
116   u32 sw_if_index = ntohl (mp->sw_if_index);
117
118   if (sw_if_index == ~0 ||
119       (table_index != ~0 && pool_is_free_index (cm->tables, table_index)))
120     {
121       rv = VNET_API_ERROR_INVALID_VALUE;
122       goto out;
123     }
124
125   /*
126    * Maybe reorder tables such that masks are most-specify to least-specific.
127    */
128   if (table_index != ~0 && mp->sort_masks)
129     table_index = classify_sort_table_chain (cm, table_index);
130
131   classify_set_pcap_chain (cm, sw_if_index, table_index);
132
133 out:
134   rmp = vl_msg_api_alloc (sizeof (*rmp));
135   rmp->_vl_msg_id =
136     ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_PCAP_SET_TABLE_REPLY);
137   rmp->context = mp->context;
138   rmp->retval = ntohl (rv);
139   rmp->table_index = htonl (table_index);
140
141   vl_api_send_msg (reg, (u8 *) rmp);
142 }
143
144 static void vl_api_classify_pcap_get_tables_t_handler
145   (vl_api_classify_pcap_get_tables_t * mp)
146 {
147   vnet_classify_main_t *cm = &vnet_classify_main;
148   vl_api_classify_pcap_get_tables_reply_t *rmp;
149   vl_api_registration_t *reg;
150   int rv = 0;
151   u32 *tables = 0;
152   u32 count;
153
154   reg = vl_api_client_index_to_registration (mp->client_index);
155   if (!reg)
156     return;
157
158   u32 sw_if_index = ntohl (mp->sw_if_index);
159   if (sw_if_index == ~0
160       || sw_if_index >= vec_len (cm->classify_table_index_by_sw_if_index))
161     {
162       rv = VNET_API_ERROR_INVALID_VALUE;
163       goto out;
164     }
165
166   u32 table_index = classify_get_pcap_chain (cm, sw_if_index);
167   if (table_index == ~0)
168     goto out;
169
170   /*
171    * Form a vector of all classifier tables in this chain.
172    */
173   vnet_classify_table_t *t;
174   u32 i;
175
176   for (i = table_index; i != ~0; i = t->next_table_index)
177     {
178       vec_add1 (tables, i);
179       t = pool_elt_at_index (cm->tables, i);
180     }
181
182 out:
183   count = vec_len (tables);
184   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
185   rmp->_vl_msg_id =
186     ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_PCAP_GET_TABLES_REPLY);
187   rmp->context = mp->context;
188   rmp->retval = ntohl (rv);
189   rmp->count = htonl (count);
190
191   for (i = 0; i < count; ++i)
192     {
193       rmp->indices[i] = htonl (tables[i]);
194     }
195
196   vec_free (tables);
197
198   vl_api_send_msg (reg, (u8 *) rmp);
199 }
200
201
202 static void vl_api_classify_trace_lookup_table_t_handler
203   (vl_api_classify_trace_lookup_table_t * mp)
204 {
205   vl_api_classify_trace_lookup_table_reply_t *rmp;
206   vl_api_registration_t *reg;
207   int rv = 0;
208   u32 table_index = ~0;
209
210   reg = vl_api_client_index_to_registration (mp->client_index);
211   if (!reg)
212     return;
213
214   u32 n_skip = ntohl (mp->skip_n_vectors);
215   u32 n_match = ntohl (mp->match_n_vectors);
216   u32 mask_len = ntohl (mp->mask_len);
217   if (n_skip > 5
218       || n_match == 0 || n_match > 5 || mask_len != n_match * sizeof (u32x4))
219     {
220       rv = VNET_API_ERROR_INVALID_VALUE;
221       goto out;
222     }
223
224   u32 table_chain;
225   table_chain = classify_get_trace_chain ();
226
227   u8 *mask_vec = 0;
228   vec_validate (mask_vec, mask_len - 1);
229   clib_memcpy (mask_vec, mp->mask, mask_len);
230
231   if (table_chain != ~0)
232     table_index = classify_lookup_chain (table_chain,
233                                          mask_vec, n_skip, n_match);
234   vec_free (mask_vec);
235
236 out:
237   rmp = vl_msg_api_alloc (sizeof (*rmp));
238   rmp->_vl_msg_id =
239     ntohs ((REPLY_MSG_ID_BASE + VL_API_CLASSIFY_TRACE_LOOKUP_TABLE_REPLY));
240   rmp->context = mp->context;
241   rmp->retval = ntohl (rv);
242   rmp->table_index = htonl (table_index);
243
244   vl_api_send_msg (reg, (u8 *) rmp);
245 }
246
247 static void vl_api_classify_trace_set_table_t_handler
248   (vl_api_classify_trace_set_table_t * mp)
249 {
250   vnet_classify_main_t *cm = &vnet_classify_main;
251   vl_api_classify_trace_set_table_reply_t *rmp;
252   vl_api_registration_t *reg;
253   int rv = 0;
254
255   reg = vl_api_client_index_to_registration (mp->client_index);
256   if (!reg)
257     return;
258
259   u32 table_index = ntohl (mp->table_index);
260   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
261     {
262       rv = VNET_API_ERROR_INVALID_VALUE;
263       goto out;
264     }
265
266   /*
267    * Maybe reorder tables such that masks are most-specific to least-specific.
268    */
269   if (table_index != ~0 && mp->sort_masks)
270     table_index = classify_sort_table_chain (cm, table_index);
271
272   classify_set_trace_chain (cm, table_index);
273
274 out:
275   rmp = vl_msg_api_alloc (sizeof (*rmp));
276   rmp->_vl_msg_id =
277     ntohs ((REPLY_MSG_ID_BASE + VL_API_CLASSIFY_TRACE_SET_TABLE_REPLY));
278   rmp->context = mp->context;
279   rmp->retval = ntohl (rv);
280   rmp->table_index = htonl (table_index);
281
282   vl_api_send_msg (reg, (u8 *) rmp);
283 }
284
285 static void vl_api_classify_trace_get_tables_t_handler
286   (vl_api_classify_trace_get_tables_t * mp)
287 {
288   vnet_classify_main_t *cm = &vnet_classify_main;
289   vl_api_classify_trace_get_tables_reply_t *rmp;
290   vl_api_registration_t *reg;
291   int rv = 0;
292   u32 *tables = 0;
293   u32 count;
294
295   reg = vl_api_client_index_to_registration (mp->client_index);
296   if (!reg)
297     return;
298
299   u32 table_index = classify_get_trace_chain ();
300   if (table_index == ~0)
301     goto out;
302
303   /*
304    * Form a vector of all classifier tables in this chain.
305    */
306   vnet_classify_table_t *t;
307   u32 i;
308
309   for (i = table_index; i != ~0; i = t->next_table_index)
310     {
311       vec_add1 (tables, i);
312       t = pool_elt_at_index (cm->tables, i);
313     }
314
315 out:
316   count = vec_len (tables);
317   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
318   rmp->_vl_msg_id =
319     ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_TRACE_GET_TABLES_REPLY);
320   rmp->context = mp->context;
321   rmp->retval = ntohl (rv);
322   rmp->count = htonl (count);
323
324   for (i = 0; i < count; ++i)
325     {
326       rmp->indices[i] = htonl (tables[i]);
327     }
328
329   vec_free (tables);
330
331   vl_api_send_msg (reg, (u8 *) rmp);
332 }
333
334
335 static void vl_api_classify_add_del_table_t_handler
336   (vl_api_classify_add_del_table_t * mp)
337 {
338   vl_api_classify_add_del_table_reply_t *rmp;
339   vnet_classify_main_t *cm = &vnet_classify_main;
340   vnet_classify_table_t *t;
341   int rv;
342
343 #define _(a) u32 a;
344   foreach_classify_add_del_table_field;
345 #undef _
346
347 #define _(a) a = ntohl(mp->a);
348   foreach_classify_add_del_table_field;
349 #undef _
350
351   if (mask_len != match_n_vectors * sizeof (u32x4))
352     {
353       rv = VNET_API_ERROR_INVALID_VALUE;
354       goto out;
355     }
356
357   /* The underlying API fails silently, on purpose, so check here */
358   if (mp->is_add == 0)          /* delete */
359     {
360       if (pool_is_free_index (cm->tables, table_index))
361         {
362           rv = VNET_API_ERROR_NO_SUCH_TABLE;
363           goto out;
364         }
365     }
366   else                          /* add or update */
367     {
368       if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
369         table_index = ~0;
370     }
371
372   u8 current_data_flag = mp->current_data_flag;
373   i16 current_data_offset = clib_net_to_host_i16 (mp->current_data_offset);
374
375   rv = vnet_classify_add_del_table
376     (cm, mp->mask, nbuckets, memory_size,
377      skip_n_vectors, match_n_vectors,
378      next_table_index, miss_next_index, &table_index,
379      current_data_flag, current_data_offset, mp->is_add, mp->del_chain);
380
381 out:
382   REPLY_MACRO2(VL_API_CLASSIFY_ADD_DEL_TABLE_REPLY,
383   ({
384     if (rv == 0 && mp->is_add)
385       {
386         t = pool_elt_at_index (cm->tables, table_index);
387         rmp->skip_n_vectors = htonl(t->skip_n_vectors);
388         rmp->match_n_vectors = htonl(t->match_n_vectors);
389         rmp->new_table_index = htonl(table_index);
390       }
391     else
392       {
393         rmp->skip_n_vectors = ~0;
394         rmp->match_n_vectors = ~0;
395         rmp->new_table_index = ~0;
396       }
397   }));
398 }
399
400 static void vl_api_classify_add_del_session_t_handler
401   (vl_api_classify_add_del_session_t * mp)
402 {
403   vnet_classify_main_t *cm = &vnet_classify_main;
404   vl_api_classify_add_del_session_reply_t *rmp;
405   int rv;
406   u32 table_index, hit_next_index, opaque_index, metadata, match_len;
407   i32 advance;
408   u8 action;
409   vnet_classify_table_t *t;
410
411   table_index = ntohl (mp->table_index);
412   hit_next_index = ntohl (mp->hit_next_index);
413   opaque_index = ntohl (mp->opaque_index);
414   advance = ntohl (mp->advance);
415   action = mp->action;
416   metadata = ntohl (mp->metadata);
417   match_len = ntohl (mp->match_len);
418
419   if (pool_is_free_index (cm->tables, table_index))
420     {
421       rv = VNET_API_ERROR_NO_SUCH_TABLE;
422       goto out;
423     }
424
425   t = pool_elt_at_index (cm->tables, table_index);
426
427   if (match_len != (t->skip_n_vectors + t->match_n_vectors) * sizeof (u32x4))
428     {
429       rv = VNET_API_ERROR_INVALID_VALUE;
430       goto out;
431     }
432
433   rv = vnet_classify_add_del_session
434     (cm, table_index, mp->match, hit_next_index, opaque_index,
435      advance, action, metadata, mp->is_add);
436
437 out:
438   REPLY_MACRO (VL_API_CLASSIFY_ADD_DEL_SESSION_REPLY);
439 }
440
441 static void
442   vl_api_policer_classify_set_interface_t_handler
443   (vl_api_policer_classify_set_interface_t * mp)
444 {
445   vlib_main_t *vm = vlib_get_main ();
446   vl_api_policer_classify_set_interface_reply_t *rmp;
447   int rv;
448   u32 sw_if_index, ip4_table_index, ip6_table_index, l2_table_index;
449
450   ip4_table_index = ntohl (mp->ip4_table_index);
451   ip6_table_index = ntohl (mp->ip6_table_index);
452   l2_table_index = ntohl (mp->l2_table_index);
453   sw_if_index = ntohl (mp->sw_if_index);
454
455   VALIDATE_SW_IF_INDEX (mp);
456
457   rv = vnet_set_policer_classify_intfc (vm, sw_if_index, ip4_table_index,
458                                         ip6_table_index, l2_table_index,
459                                         mp->is_add);
460
461   BAD_SW_IF_INDEX_LABEL;
462
463   REPLY_MACRO (VL_API_POLICER_CLASSIFY_SET_INTERFACE_REPLY);
464 }
465
466 static void
467 send_policer_classify_details (u32 sw_if_index,
468                                u32 table_index, vl_api_registration_t * reg,
469                                u32 context)
470 {
471   vl_api_policer_classify_details_t *mp;
472
473   mp = vl_msg_api_alloc (sizeof (*mp));
474   clib_memset (mp, 0, sizeof (*mp));
475   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_POLICER_CLASSIFY_DETAILS);
476   mp->context = context;
477   mp->sw_if_index = htonl (sw_if_index);
478   mp->table_index = htonl (table_index);
479
480   vl_api_send_msg (reg, (u8 *) mp);
481 }
482
483 static void
484 vl_api_policer_classify_dump_t_handler (vl_api_policer_classify_dump_t * mp)
485 {
486   vl_api_registration_t *reg;
487   policer_classify_main_t *pcm = &policer_classify_main;
488   u32 *vec_tbl;
489   int i;
490   u32 filter_sw_if_index;
491
492   reg = vl_api_client_index_to_registration (mp->client_index);
493   if (!reg)
494     return;
495
496   filter_sw_if_index = ntohl (mp->sw_if_index);
497   if (filter_sw_if_index
498       >= vec_len (pcm->classify_table_index_by_sw_if_index[mp->type]))
499     return;
500
501   if (filter_sw_if_index != ~0)
502     vec_tbl =
503       &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
504   else
505     vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
506
507   if (vec_len (vec_tbl))
508     {
509       for (i = 0; i < vec_len (vec_tbl); i++)
510         {
511           if (vec_elt (vec_tbl, i) == ~0)
512             continue;
513
514           send_policer_classify_details (i, vec_elt (vec_tbl, i), reg,
515                                          mp->context);
516         }
517     }
518 }
519
520 static void
521 vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t * mp)
522 {
523   vl_api_registration_t *reg;
524
525   reg = vl_api_client_index_to_registration (mp->client_index);
526   if (!reg)
527     return;
528
529   vnet_classify_main_t *cm = &vnet_classify_main;
530   vnet_classify_table_t *t;
531   u32 *table_ids = 0;
532   u32 count;
533
534    pool_foreach (t, cm->tables)
535     {
536      vec_add1 (table_ids, ntohl(t - cm->tables));
537    }
538   count = vec_len (table_ids);
539
540   vl_api_classify_table_ids_reply_t *rmp;
541   rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp) + count * sizeof (u32));
542   rmp->_vl_msg_id =
543     ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_TABLE_IDS_REPLY);
544   rmp->context = mp->context;
545   rmp->count = ntohl (count);
546   clib_memcpy (rmp->ids, table_ids, count * sizeof (u32));
547   rmp->retval = 0;
548
549   vl_api_send_msg (reg, (u8 *) rmp);
550
551   vec_free (table_ids);
552 }
553
554 static void
555   vl_api_classify_table_by_interface_t_handler
556   (vl_api_classify_table_by_interface_t * mp)
557 {
558   vl_api_classify_table_by_interface_reply_t *rmp;
559   int rv = 0;
560
561   u32 sw_if_index = ntohl (mp->sw_if_index);
562   u32 *acl = 0;
563
564   vec_validate (acl, IN_OUT_ACL_N_TABLES - 1);
565   vec_set (acl, ~0);
566
567   VALIDATE_SW_IF_INDEX (mp);
568
569   in_out_acl_main_t *am = &in_out_acl_main;
570
571   int if_idx;
572   u32 type;
573
574   for (type = 0; type < IN_OUT_ACL_N_TABLES; type++)
575     {
576       u32 *vec_tbl =
577         am->classify_table_index_by_sw_if_index[IN_OUT_ACL_INPUT_TABLE_GROUP]
578         [type];
579       if (vec_len (vec_tbl))
580         {
581           for (if_idx = 0; if_idx < vec_len (vec_tbl); if_idx++)
582             {
583               if (vec_elt (vec_tbl, if_idx) == ~0 || sw_if_index != if_idx)
584                 {
585                   continue;
586                 }
587               acl[type] = vec_elt (vec_tbl, if_idx);
588             }
589         }
590     }
591
592   BAD_SW_IF_INDEX_LABEL;
593
594    REPLY_MACRO2(VL_API_CLASSIFY_TABLE_BY_INTERFACE_REPLY,
595    ({
596      rmp->sw_if_index = ntohl(sw_if_index);
597      rmp->l2_table_id = ntohl(acl[IN_OUT_ACL_TABLE_L2]);
598      rmp->ip4_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP4]);
599      rmp->ip6_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP6]);
600    }));
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   pool_foreach (t, cm->tables)
620     {
621       if (table_id == t - cm->tables)
622         {
623           rmp = vl_msg_api_alloc_as_if_client (
624             sizeof (*rmp) + t->match_n_vectors * sizeof (u32x4));
625           rmp->_vl_msg_id =
626             ntohs (REPLY_MSG_ID_BASE + 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,
637                        t->match_n_vectors * sizeof (u32x4));
638           rmp->retval = 0;
639           break;
640         }
641     }
642
643   if (rmp == 0)
644     {
645       rmp = vl_msg_api_alloc (sizeof (*rmp));
646       rmp->_vl_msg_id =
647         ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_TABLE_INFO_REPLY);
648       rmp->context = mp->context;
649       rmp->retval = ntohl (VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND);
650     }
651
652   vl_api_send_msg (reg, (u8 *) rmp);
653 }
654
655 static void
656 send_classify_session_details (vl_api_registration_t * reg,
657                                u32 table_id,
658                                u32 match_length,
659                                vnet_classify_entry_t * e, u32 context)
660 {
661   vl_api_classify_session_details_t *rmp;
662
663   rmp = vl_msg_api_alloc (sizeof (*rmp) + match_length);
664   clib_memset (rmp, 0, sizeof (*rmp));
665   rmp->_vl_msg_id =
666     ntohs (REPLY_MSG_ID_BASE + VL_API_CLASSIFY_SESSION_DETAILS);
667   rmp->context = context;
668   rmp->table_id = ntohl (table_id);
669   rmp->hit_next_index = ntohl (e->next_index);
670   rmp->advance = ntohl (e->advance);
671   rmp->opaque_index = ntohl (e->opaque_index);
672   rmp->match_length = ntohl (match_length);
673   clib_memcpy (rmp->match, e->key, match_length);
674
675   vl_api_send_msg (reg, (u8 *) rmp);
676 }
677
678 static void
679 vl_api_classify_session_dump_t_handler (vl_api_classify_session_dump_t * mp)
680 {
681   vnet_classify_main_t *cm = &vnet_classify_main;
682   vl_api_registration_t *reg;
683
684   u32 table_id = ntohl (mp->table_id);
685   vnet_classify_table_t *t;
686
687   reg = vl_api_client_index_to_registration (mp->client_index);
688   if (!reg)
689     return;
690
691   pool_foreach (t, cm->tables)
692    {
693     if (table_id == t - cm->tables)
694       {
695         vnet_classify_bucket_t * b;
696         vnet_classify_entry_t * v, * save_v;
697         int i, j, k;
698
699         for (i = 0; i < t->nbuckets; i++)
700           {
701             b = &t->buckets [i];
702             if (b->offset == 0)
703               continue;
704
705             save_v = vnet_classify_get_entry (t, b->offset);
706             for (j = 0; j < (1<<b->log2_pages); j++)
707               {
708                 for (k = 0; k < t->entries_per_page; k++)
709                   {
710                     v = vnet_classify_entry_at_index
711                       (t, save_v, j*t->entries_per_page + k);
712                     if (vnet_classify_entry_is_free (v))
713                       continue;
714
715                     send_classify_session_details
716                       (reg, table_id, t->match_n_vectors * sizeof (u32x4),
717                        v, mp->context);
718                   }
719               }
720           }
721         break;
722       }
723   }
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 (REPLY_MSG_ID_BASE + 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
891 vl_api_punt_acl_add_del_t_handler (vl_api_punt_acl_add_del_t *mp)
892 {
893   vlib_main_t *vm = vlib_get_main ();
894   vl_api_punt_acl_add_del_reply_t *rmp;
895   int rv;
896
897   rv = vnet_set_in_out_acl_intfc (
898     vm, 0 /* sw_if_index */, ~0 /* ip4_table_index */,
899     ~0 /* ip6_table_index */, ~0 /* l2_table_index */,
900     ntohl (mp->ip4_table_index), ntohl (mp->ip6_table_index), mp->is_add,
901     0 /* is_output */);
902
903   REPLY_MACRO (VL_API_PUNT_ACL_ADD_DEL_REPLY);
904 }
905
906 static void
907 vl_api_punt_acl_get_t_handler (vl_api_punt_acl_get_t *mp)
908 {
909   vl_api_punt_acl_get_reply_t *rmp;
910   int rv = 0;
911
912   const in_out_acl_main_t *am = &in_out_acl_main;
913
914   u32 *const *tables =
915     am->classify_table_index_by_sw_if_index[IN_OUT_ACL_INPUT_TABLE_GROUP];
916   const u32 *ip4_table = tables[IN_OUT_ACL_TABLE_IP4_PUNT];
917   const u32 *ip6_table = tables[IN_OUT_ACL_TABLE_IP6_PUNT];
918   const u32 ip4_table_index = vec_len (ip4_table) ? ip4_table[0] : ~0;
919   const u32 ip6_table_index = vec_len (ip6_table) ? ip6_table[0] : ~0;
920
921   REPLY_MACRO2 (VL_API_PUNT_ACL_GET_REPLY, ({
922                   rmp->ip4_table_index = ntohl (ip4_table_index);
923                   rmp->ip6_table_index = ntohl (ip6_table_index);
924                 }));
925 }
926
927 static void vl_api_output_acl_set_interface_t_handler
928   (vl_api_output_acl_set_interface_t * mp)
929 {
930   vlib_main_t *vm = vlib_get_main ();
931   vl_api_output_acl_set_interface_reply_t *rmp;
932   int rv;
933
934   VALIDATE_SW_IF_INDEX (mp);
935
936   u32 ip4_table_index = ntohl (mp->ip4_table_index);
937   u32 ip6_table_index = ntohl (mp->ip6_table_index);
938   u32 l2_table_index = ntohl (mp->l2_table_index);
939   u32 sw_if_index = ntohl (mp->sw_if_index);
940
941   rv = vnet_set_output_acl_intfc (vm, sw_if_index, ip4_table_index,
942                                   ip6_table_index, l2_table_index,
943                                   mp->is_add);
944
945   BAD_SW_IF_INDEX_LABEL;
946
947   REPLY_MACRO (VL_API_OUTPUT_ACL_SET_INTERFACE_REPLY);
948 }
949
950 #include <classify/classify.api.c>
951
952 static clib_error_t *
953 classify_api_hookup (vlib_main_t * vm)
954 {
955   api_main_t *am = vlibapi_get_main ();
956
957   /*
958    * Trace space for classifier mask+match
959    */
960   vl_api_increase_msg_trace_size (am, VL_API_CLASSIFY_ADD_DEL_TABLE,
961                                   5 * sizeof (u32x4));
962   vl_api_increase_msg_trace_size (am, VL_API_CLASSIFY_ADD_DEL_SESSION,
963                                   5 * sizeof (u32x4));
964
965   /*
966    * Set up the (msg_name, crc, message-id) table
967    */
968   msg_id_base = setup_message_id_table ();
969
970   return 0;
971 }
972
973 VLIB_API_INIT_FUNCTION (classify_api_hookup);
974
975 /*
976  * fd.io coding-style-patch-verification: ON
977  *
978  * Local Variables:
979  * eval: (c-set-style "gnu")
980  * End:
981  */