GBP: fix UT after multi-arch change
[vpp.git] / src / plugins / gbp / gbp_classify_node.c
1 /*
2  * gbp.h : Group Based Policy
3  *
4  * Copyright (c) 2018 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <plugins/gbp/gbp.h>
19 #include <plugins/gbp/gbp_classify.h>
20 #include <plugins/gbp/gbp_policy_dpo.h>
21 #include <plugins/gbp/gbp_ext_itf.h>
22 #include <vnet/fib/ip4_fib.h>
23 #include <vnet/fib/ip6_fib.h>
24 #include <vnet/dpo/load_balance.h>
25 #include <vnet/l2/l2_input.h>
26 #include <vnet/l2/feat_bitmap.h>
27 #include <vnet/fib/fib_table.h>
28 #include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
29
30 /**
31  * per-packet trace data
32  */
33 typedef struct gbp_classify_trace_t_
34 {
35   /* per-pkt trace data */
36   epg_id_t src_epg;
37 } gbp_classify_trace_t;
38
39 /*
40  * determine the SRC EPG form the input port
41  */
42 always_inline uword
43 gbp_classify_inline (vlib_main_t * vm,
44                      vlib_node_runtime_t * node,
45                      vlib_frame_t * frame,
46                      gbp_src_classify_type_t type, dpo_proto_t dproto)
47 {
48   gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
49   u32 n_left_from, *from, *to_next;
50   u32 next_index;
51
52   next_index = 0;
53   n_left_from = frame->n_vectors;
54   from = vlib_frame_vector_args (frame);
55
56   while (n_left_from > 0)
57     {
58       u32 n_left_to_next;
59
60       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
61
62       while (n_left_from > 0 && n_left_to_next > 0)
63         {
64           u32 next0, bi0, src_epg, sw_if_index0;
65           const gbp_endpoint_t *ge0;
66           vlib_buffer_t *b0;
67
68           bi0 = from[0];
69           to_next[0] = bi0;
70           from += 1;
71           to_next += 1;
72           n_left_from -= 1;
73           n_left_to_next -= 1;
74
75           b0 = vlib_get_buffer (vm, bi0);
76
77           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
78           vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_NONE;
79
80           if (GBP_SRC_CLASSIFY_NULL == type)
81             {
82               src_epg = EPG_INVALID;
83               next0 =
84                 vnet_l2_feature_next (b0, gscm->l2_input_feat_next[type],
85                                       L2INPUT_FEAT_GBP_NULL_CLASSIFY);
86             }
87           else
88             {
89               if (DPO_PROTO_ETHERNET == dproto)
90                 {
91                   const ethernet_header_t *h0;
92
93                   h0 = vlib_buffer_get_current (b0);
94                   next0 =
95                     vnet_l2_feature_next (b0, gscm->l2_input_feat_next[type],
96                                           L2INPUT_FEAT_GBP_SRC_CLASSIFY);
97                   ge0 = gbp_endpoint_find_mac (h0->src_address,
98                                                vnet_buffer (b0)->l2.bd_index);
99                 }
100               else if (DPO_PROTO_IP4 == dproto)
101                 {
102                   const ip4_header_t *h0;
103
104                   h0 = vlib_buffer_get_current (b0);
105
106                   ge0 = gbp_endpoint_find_ip4
107                     (&h0->src_address,
108                      fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
109                                                           sw_if_index0));
110
111
112                   /*
113                    * Go straight to looukp, do not pass go, do not collect $200
114                    */
115                   next0 = 0;
116                 }
117               else if (DPO_PROTO_IP6 == dproto)
118                 {
119                   const ip6_header_t *h0;
120
121                   h0 = vlib_buffer_get_current (b0);
122
123                   ge0 = gbp_endpoint_find_ip6
124                     (&h0->src_address,
125                      fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6,
126                                                           sw_if_index0));
127
128
129                   /*
130                    * Go straight to lookup, do not pass go, do not collect $200
131                    */
132                   next0 = 0;
133                 }
134               else
135                 {
136                   ge0 = NULL;
137                   next0 = 0;
138                   ASSERT (0);
139                 }
140
141               if (PREDICT_TRUE (NULL != ge0))
142                 src_epg = ge0->ge_fwd.gef_epg_id;
143               else
144                 src_epg = EPG_INVALID;
145             }
146
147           vnet_buffer2 (b0)->gbp.src_epg = src_epg;
148
149           if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
150             {
151               gbp_classify_trace_t *t =
152                 vlib_add_trace (vm, node, b0, sizeof (*t));
153               t->src_epg = src_epg;
154             }
155
156           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
157                                            to_next, n_left_to_next,
158                                            bi0, next0);
159         }
160
161       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
162     }
163
164   return frame->n_vectors;
165 }
166
167 VLIB_NODE_FN (gbp_src_classify_node) (vlib_main_t * vm,
168                                       vlib_node_runtime_t * node,
169                                       vlib_frame_t * frame)
170 {
171   return (gbp_classify_inline (vm, node, frame,
172                                GBP_SRC_CLASSIFY_PORT, DPO_PROTO_ETHERNET));
173 }
174
175 VLIB_NODE_FN (gbp_null_classify_node) (vlib_main_t * vm,
176                                        vlib_node_runtime_t * node,
177                                        vlib_frame_t * frame)
178 {
179   return (gbp_classify_inline (vm, node, frame,
180                                GBP_SRC_CLASSIFY_NULL, DPO_PROTO_ETHERNET));
181 }
182
183 VLIB_NODE_FN (gbp_ip4_src_classify_node) (vlib_main_t * vm,
184                                           vlib_node_runtime_t * node,
185                                           vlib_frame_t * frame)
186 {
187   return (gbp_classify_inline (vm, node, frame,
188                                GBP_SRC_CLASSIFY_PORT, DPO_PROTO_IP4));
189 }
190
191 VLIB_NODE_FN (gbp_ip6_src_classify_node) (vlib_main_t * vm,
192                                           vlib_node_runtime_t * node,
193                                           vlib_frame_t * frame)
194 {
195   return (gbp_classify_inline (vm, node, frame,
196                                GBP_SRC_CLASSIFY_PORT, DPO_PROTO_IP6));
197 }
198
199
200 /* packet trace format function */
201 static u8 *
202 format_gbp_classify_trace (u8 * s, va_list * args)
203 {
204   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
205   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
206   gbp_classify_trace_t *t = va_arg (*args, gbp_classify_trace_t *);
207
208   s = format (s, "src-epg:%d", t->src_epg);
209
210   return s;
211 }
212
213 /* *INDENT-OFF* */
214 VLIB_REGISTER_NODE (gbp_null_classify_node) = {
215   .name = "gbp-null-classify",
216   .vector_size = sizeof (u32),
217   .format_trace = format_gbp_classify_trace,
218   .type = VLIB_NODE_TYPE_INTERNAL,
219
220   .n_errors = 0,
221   .n_next_nodes = 0,
222 };
223
224 VLIB_REGISTER_NODE (gbp_src_classify_node) = {
225   .name = "gbp-src-classify",
226   .vector_size = sizeof (u32),
227   .format_trace = format_gbp_classify_trace,
228   .type = VLIB_NODE_TYPE_INTERNAL,
229
230   .n_errors = 0,
231   .n_next_nodes = 0,
232 };
233
234 VLIB_REGISTER_NODE (gbp_ip4_src_classify_node) = {
235   .name = "ip4-gbp-src-classify",
236   .vector_size = sizeof (u32),
237   .format_trace = format_gbp_classify_trace,
238   .type = VLIB_NODE_TYPE_INTERNAL,
239
240   .n_errors = 0,
241   .n_next_nodes = 1,
242   .next_nodes = {
243     [0] = "ip4-lookup"
244   },
245 };
246
247 VLIB_REGISTER_NODE (gbp_ip6_src_classify_node) = {
248   .name = "ip6-gbp-src-classify",
249   .vector_size = sizeof (u32),
250   .format_trace = format_gbp_classify_trace,
251   .type = VLIB_NODE_TYPE_INTERNAL,
252
253   .n_errors = 0,
254   .n_next_nodes = 1,
255   .next_nodes = {
256     [0] = "ip6-lookup"
257   },
258 };
259
260 VNET_FEATURE_INIT (gbp_ip4_src_classify_feat_node, static) =
261 {
262   .arc_name = "ip4-unicast",
263   .node_name = "ip4-gbp-src-classify",
264   .runs_before = VNET_FEATURES ("nat44-out2in"),
265 };
266 VNET_FEATURE_INIT (gbp_ip6_src_classify_feat_node, static) =
267 {
268   .arc_name = "ip6-unicast",
269   .node_name = "ip6-gbp-src-classify",
270   .runs_before = VNET_FEATURES ("nat66-out2in"),
271 };
272
273 /* *INDENT-ON* */
274
275 typedef enum gbp_lpm_classify_next_t_
276 {
277   GPB_LPM_CLASSIFY_DROP,
278 } gbp_lpm_classify_next_t;
279
280 always_inline dpo_proto_t
281 ethertype_to_dpo_proto (const ethernet_header_t * eh0)
282 {
283   u16 etype = clib_net_to_host_u16 (eh0->type);
284
285   switch (etype)
286     {
287     case ETHERNET_TYPE_IP4:
288       return (DPO_PROTO_IP4);
289     case ETHERNET_TYPE_IP6:
290       return (DPO_PROTO_IP6);
291     case ETHERNET_TYPE_VLAN:
292       {
293         ethernet_vlan_header_t *vh0;
294
295         vh0 = (ethernet_vlan_header_t *) (eh0 + 1);
296
297         switch (clib_net_to_host_u16 (vh0->type))
298           {
299           case ETHERNET_TYPE_IP4:
300             return (DPO_PROTO_IP4);
301           case ETHERNET_TYPE_IP6:
302             return (DPO_PROTO_IP6);
303           }
304       }
305     }
306
307   return (DPO_PROTO_NONE);
308 }
309
310 /*
311  * Determine the SRC EPG from a LPM
312  */
313 always_inline uword
314 gbp_lpm_classify_inline (vlib_main_t * vm,
315                          vlib_node_runtime_t * node,
316                          vlib_frame_t * frame,
317                          dpo_proto_t dproto, u8 is_recirc)
318 {
319   gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
320   u32 n_left_from, *from, *to_next;
321   u32 next_index;
322
323   next_index = 0;
324   n_left_from = frame->n_vectors;
325   from = vlib_frame_vector_args (frame);
326
327   while (n_left_from > 0)
328     {
329       u32 n_left_to_next;
330
331       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
332
333       while (n_left_from > 0 && n_left_to_next > 0)
334         {
335           u32 bi0, sw_if_index0, fib_index0, lbi0;
336           gbp_lpm_classify_next_t next0;
337           const gbp_policy_dpo_t *gpd0;
338           const gbp_ext_itf_t *gx0;
339           const gbp_recirc_t *gr0;
340           const dpo_id_t *dpo0;
341           load_balance_t *lb0;
342           ip4_header_t *ip4_0;
343           ip6_header_t *ip6_0;
344           vlib_buffer_t *b0;
345           epg_id_t src_epg0;
346
347           bi0 = from[0];
348           to_next[0] = bi0;
349           from += 1;
350           to_next += 1;
351           n_left_from -= 1;
352           n_left_to_next -= 1;
353           ip4_0 = NULL;
354           ip6_0 = NULL;
355           next0 = GPB_LPM_CLASSIFY_DROP;
356
357           b0 = vlib_get_buffer (vm, bi0);
358
359           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
360           vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_NONE;
361
362           if (DPO_PROTO_IP4 == dproto)
363             ip4_0 = vlib_buffer_get_current (b0);
364           else if (DPO_PROTO_IP6 == dproto)
365             ip6_0 = vlib_buffer_get_current (b0);
366           else if (DPO_PROTO_ETHERNET == dproto)
367             {
368               const ethernet_header_t *eh0;
369
370               eh0 = vlib_buffer_get_current (b0);
371
372               dproto = ethertype_to_dpo_proto (eh0);
373
374               switch (dproto)
375                 {
376                 case DPO_PROTO_IP4:
377                   ip4_0 = (vlib_buffer_get_current (b0) +
378                            vnet_buffer (b0)->l2.l2_len);
379                   break;
380                 case DPO_PROTO_IP6:
381                   ip6_0 = (vlib_buffer_get_current (b0) +
382                            vnet_buffer (b0)->l2.l2_len);
383                   break;
384                 default:
385                   /* not IP so no LPM classify possible */
386                   src_epg0 = EPG_INVALID;
387                   goto trace;
388                 }
389             }
390
391           if (is_recirc)
392             {
393               gr0 = gbp_recirc_get (sw_if_index0);
394               fib_index0 = gr0->gr_fib_index[dproto];
395
396               vnet_feature_next (&next0, b0);
397             }
398           else
399             {
400               gx0 = gbp_ext_itf_get (sw_if_index0);
401               fib_index0 = gx0->gx_fib_index[dproto];
402
403               next0 = vnet_l2_feature_next
404                 (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM],
405                  L2INPUT_FEAT_GBP_LPM_CLASSIFY);
406             }
407
408           if (DPO_PROTO_IP4 == dproto)
409             {
410               lbi0 = ip4_fib_forwarding_lookup (fib_index0,
411                                                 &ip4_0->src_address);
412             }
413           else if (DPO_PROTO_IP6 == dproto)
414             {
415               lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
416                                                   &ip6_0->src_address);
417             }
418           else
419             {
420               /* not IP so no LPM classify possible */
421               src_epg0 = EPG_INVALID;
422               goto trace;
423             }
424           lb0 = load_balance_get (lbi0);
425           dpo0 = load_balance_get_bucket_i (lb0, 0);
426
427           if (gbp_policy_dpo_type == dpo0->dpoi_type)
428             {
429               gpd0 = gbp_policy_dpo_get (dpo0->dpoi_index);
430               src_epg0 = gpd0->gpd_epg;
431             }
432           else
433             {
434               /* could not classify => drop */
435               src_epg0 = EPG_INVALID;
436               next0 = GPB_LPM_CLASSIFY_DROP;
437             }
438
439         trace:
440           vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
441
442           if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
443             {
444               gbp_classify_trace_t *t =
445                 vlib_add_trace (vm, node, b0, sizeof (*t));
446               t->src_epg = src_epg0;
447             }
448
449           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
450                                            to_next, n_left_to_next,
451                                            bi0, next0);
452         }
453
454       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
455     }
456
457   return frame->n_vectors;
458 }
459
460 VLIB_NODE_FN (gbp_ip4_lpm_classify_node) (vlib_main_t * vm,
461                                           vlib_node_runtime_t * node,
462                                           vlib_frame_t * frame)
463 {
464   return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP4, 1));
465 }
466
467 VLIB_NODE_FN (gbp_ip6_lpm_classify_node) (vlib_main_t * vm,
468                                           vlib_node_runtime_t * node,
469                                           vlib_frame_t * frame)
470 {
471   return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP6, 1));
472 }
473
474 VLIB_NODE_FN (gbp_l2_lpm_classify_node) (vlib_main_t * vm,
475                                          vlib_node_runtime_t * node,
476                                          vlib_frame_t * frame)
477 {
478   return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
479 }
480
481 /* *INDENT-OFF* */
482 VLIB_REGISTER_NODE (gbp_ip4_lpm_classify_node) = {
483   .name = "ip4-gbp-lpm-classify",
484   .vector_size = sizeof (u32),
485   .format_trace = format_gbp_classify_trace,
486   .type = VLIB_NODE_TYPE_INTERNAL,
487
488   .n_errors = 0,
489   .n_next_nodes = 1,
490   .next_nodes = {
491     [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
492   },
493 };
494
495 VLIB_REGISTER_NODE (gbp_ip6_lpm_classify_node) = {
496   .name = "ip6-gbp-lpm-classify",
497   .vector_size = sizeof (u32),
498   .format_trace = format_gbp_classify_trace,
499   .type = VLIB_NODE_TYPE_INTERNAL,
500
501   .n_errors = 0,
502   .n_next_nodes = 1,
503   .next_nodes = {
504     [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
505   },
506 };
507
508 VLIB_REGISTER_NODE (gbp_l2_lpm_classify_node) = {
509   .name = "l2-gbp-lpm-classify",
510   .vector_size = sizeof (u32),
511   .format_trace = format_gbp_classify_trace,
512   .type = VLIB_NODE_TYPE_INTERNAL,
513
514   .n_errors = 0,
515   .n_next_nodes = 1,
516   .next_nodes = {
517     [GPB_LPM_CLASSIFY_DROP] = "error-drop"
518   },
519 };
520
521 VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
522 {
523   .arc_name = "ip4-unicast",
524   .node_name = "ip4-gbp-lpm-classify",
525   .runs_before = VNET_FEATURES ("nat44-out2in"),
526 };
527 VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
528 {
529   .arc_name = "ip6-unicast",
530   .node_name = "ip6-gbp-lpm-classify",
531   .runs_before = VNET_FEATURES ("nat66-out2in"),
532 };
533
534 /* *INDENT-ON* */
535
536 /*
537  * fd.io coding-style-patch-verification: ON
538  *
539  * Local Variables:
540  * eval: (c-set-style "gnu")
541  * End:
542  */