GBP: Sclass to src-epg conversions
[vpp.git] / src / plugins / gbp / gbp_sclass.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <plugins/gbp/gbp.h>
17 #include <vnet/l2/l2_input.h>
18 #include <vnet/l2/l2_output.h>
19
20 /**
21  * Grouping of global data for the GBP source EPG classification feature
22  */
23 typedef struct gbp_sclass_main_t_
24 {
25   /**
26    * Next nodes for L2 output features
27    */
28   u32 gel_l2_input_feat_next[32];
29   u32 gel_l2_output_feat_next[32];
30 } gbp_sclass_main_t;
31
32 static gbp_sclass_main_t gbp_sclass_main;
33
34 #define foreach_gbp_sclass                      \
35   _(DROP,    "drop")
36
37
38 typedef enum
39 {
40 #define _(sym,str) GBP_SCLASS_NEXT_##sym,
41   foreach_gbp_sclass
42 #undef _
43     GBP_SCLASS_N_NEXT,
44 } gbp_sclass_next_t;
45
46 typedef struct gbp_sclass_trace_t_
47 {
48   /* per-pkt trace data */
49   u32 epg;
50   u32 sclass;
51 } gbp_sclass_trace_t;
52
53 always_inline uword
54 gbp_sclass_inline (vlib_main_t * vm,
55                    vlib_node_runtime_t * node,
56                    vlib_frame_t * frame, int is_id_2_sclass, int is_l2)
57 {
58   u32 n_left_from, *from, *to_next, next_index;
59   gbp_sclass_main_t *glm;
60
61   glm = &gbp_sclass_main;
62   next_index = 0;
63   n_left_from = frame->n_vectors;
64   from = vlib_frame_vector_args (frame);
65
66   while (n_left_from > 0)
67     {
68       u32 n_left_to_next;
69
70       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
71
72       while (n_left_from > 0 && n_left_to_next > 0)
73         {
74           gbp_sclass_next_t next0;
75           vlib_buffer_t *b0;
76           epg_id_t epg0;
77           u16 sclass0;
78           u32 bi0;
79
80           next0 = GBP_SCLASS_NEXT_DROP;
81           bi0 = from[0];
82           to_next[0] = bi0;
83           from += 1;
84           to_next += 1;
85           n_left_from -= 1;
86           n_left_to_next -= 1;
87
88           b0 = vlib_get_buffer (vm, bi0);
89
90           if (is_id_2_sclass)
91             {
92               // output direction - convert from the SRC-EPD to the sclass
93               gbp_endpoint_group_t *gg;
94
95               epg0 = vnet_buffer2 (b0)->gbp.src_epg;
96               gg = gbp_epg_get (epg0);
97
98               if (NULL != gg)
99                 {
100                   sclass0 = vnet_buffer2 (b0)->gbp.sclass = gg->gg_sclass;
101                   if (is_l2)
102                     next0 =
103                       vnet_l2_feature_next (b0, glm->gel_l2_output_feat_next,
104                                             L2OUTPUT_FEAT_GBP_ID_2_SCLASS);
105                   else
106                     vnet_feature_next (&next0, b0);
107                 }
108               else
109                 sclass0 = 0;
110             }
111           else
112             {
113               /* input direction - convert from the sclass to the SRC-EGD */
114               sclass0 = vnet_buffer2 (b0)->gbp.sclass;
115               vnet_buffer2 (b0)->gbp.src_epg =
116                 gbp_epg_sclass_2_id (vnet_buffer2 (b0)->gbp.sclass);
117               epg0 = vnet_buffer2 (b0)->gbp.src_epg;
118
119               if (EPG_INVALID != epg0)
120                 {
121                   if (is_l2)
122                     next0 =
123                       vnet_l2_feature_next (b0, glm->gel_l2_input_feat_next,
124                                             L2INPUT_FEAT_GBP_SCLASS_2_ID);
125                   else
126                     vnet_feature_next (&next0, b0);
127                 }
128             }
129
130           if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
131             {
132               gbp_sclass_trace_t *t =
133                 vlib_add_trace (vm, node, b0, sizeof (*t));
134               t->epg = epg0;
135               t->sclass = sclass0;
136             }
137
138           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
139                                            to_next, n_left_to_next,
140                                            bi0, next0);
141         }
142
143       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
144     }
145
146   return frame->n_vectors;
147 }
148
149 always_inline uword
150 l2_gbp_id_2_sclass (vlib_main_t * vm,
151                     vlib_node_runtime_t * node, vlib_frame_t * frame)
152 {
153   return (gbp_sclass_inline (vm, node, frame, 1, 1));
154 }
155
156 always_inline uword
157 l2_gbp_sclass_2_id (vlib_main_t * vm,
158                     vlib_node_runtime_t * node, vlib_frame_t * frame)
159 {
160   return (gbp_sclass_inline (vm, node, frame, 0, 1));
161 }
162
163 always_inline uword
164 ip4_gbp_id_2_sclass (vlib_main_t * vm,
165                      vlib_node_runtime_t * node, vlib_frame_t * frame)
166 {
167   return (gbp_sclass_inline (vm, node, frame, 1, 0));
168 }
169
170 always_inline uword
171 ip4_gbp_sclass_2_id (vlib_main_t * vm,
172                      vlib_node_runtime_t * node, vlib_frame_t * frame)
173 {
174   return (gbp_sclass_inline (vm, node, frame, 0, 0));
175 }
176
177 always_inline uword
178 ip6_gbp_id_2_sclass (vlib_main_t * vm,
179                      vlib_node_runtime_t * node, vlib_frame_t * frame)
180 {
181   return (gbp_sclass_inline (vm, node, frame, 1, 0));
182 }
183
184 always_inline uword
185 ip6_gbp_sclass_2_id (vlib_main_t * vm,
186                      vlib_node_runtime_t * node, vlib_frame_t * frame)
187 {
188   return (gbp_sclass_inline (vm, node, frame, 0, 0));
189 }
190
191 /* packet trace format function */
192 static u8 *
193 format_gbp_sclass_trace (u8 * s, va_list * args)
194 {
195   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
196   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
197   gbp_sclass_trace_t *t = va_arg (*args, gbp_sclass_trace_t *);
198
199   s = format (s, "epg:%d sclass:%d", t->epg, t->sclass);
200
201   return s;
202 }
203
204 /* *INDENT-OFF* */
205 VLIB_REGISTER_NODE (l2_gbp_id_2_sclass_node) = {
206   .function = l2_gbp_id_2_sclass,
207   .name = "l2-gbp-id-2-sclass",
208   .vector_size = sizeof (u32),
209   .format_trace = format_gbp_sclass_trace,
210   .type = VLIB_NODE_TYPE_INTERNAL,
211
212   .n_next_nodes = GBP_SCLASS_N_NEXT,
213
214   .next_nodes = {
215     [GBP_SCLASS_NEXT_DROP] = "error-drop",
216   },
217 };
218 VLIB_REGISTER_NODE (l2_gbp_sclass_2_id_node) = {
219   .function = l2_gbp_sclass_2_id,
220   .name = "l2-gbp-sclass-2-id",
221   .vector_size = sizeof (u32),
222   .format_trace = format_gbp_sclass_trace,
223   .type = VLIB_NODE_TYPE_INTERNAL,
224
225   .n_next_nodes = GBP_SCLASS_N_NEXT,
226
227   .next_nodes = {
228     [GBP_SCLASS_NEXT_DROP] = "error-drop",
229   },
230 };
231
232 VLIB_REGISTER_NODE (ip4_gbp_id_2_sclass_node) = {
233   .function = ip4_gbp_id_2_sclass,
234   .name = "ip4-gbp-id-2-sclass",
235   .vector_size = sizeof (u32),
236   .format_trace = format_gbp_sclass_trace,
237   .type = VLIB_NODE_TYPE_INTERNAL,
238
239   .n_next_nodes = GBP_SCLASS_N_NEXT,
240
241   .next_nodes = {
242     [GBP_SCLASS_NEXT_DROP] = "error-drop",
243   },
244 };
245 VLIB_REGISTER_NODE (ip4_gbp_sclass_2_id_node) = {
246   .function = ip4_gbp_sclass_2_id,
247   .name = "ip4-gbp-sclass-2-id",
248   .vector_size = sizeof (u32),
249   .format_trace = format_gbp_sclass_trace,
250   .type = VLIB_NODE_TYPE_INTERNAL,
251
252   .n_next_nodes = GBP_SCLASS_N_NEXT,
253
254   .next_nodes = {
255     [GBP_SCLASS_NEXT_DROP] = "error-drop",
256   },
257 };
258
259 VLIB_REGISTER_NODE (ip6_gbp_id_2_sclass_node) = {
260   .function = ip6_gbp_id_2_sclass,
261   .name = "ip6-gbp-id-2-sclass",
262   .vector_size = sizeof (u32),
263   .format_trace = format_gbp_sclass_trace,
264   .type = VLIB_NODE_TYPE_INTERNAL,
265
266   .n_next_nodes = GBP_SCLASS_N_NEXT,
267
268   .next_nodes = {
269     [GBP_SCLASS_NEXT_DROP] = "error-drop",
270   },
271 };
272 VLIB_REGISTER_NODE (ip6_gbp_sclass_2_id_node) = {
273   .function = ip6_gbp_sclass_2_id,
274   .name = "ip6-gbp-sclass-2-id",
275   .vector_size = sizeof (u32),
276   .format_trace = format_gbp_sclass_trace,
277   .type = VLIB_NODE_TYPE_INTERNAL,
278
279   .n_next_nodes = GBP_SCLASS_N_NEXT,
280
281   .next_nodes = {
282     [GBP_SCLASS_NEXT_DROP] = "error-drop",
283   },
284 };
285
286 VLIB_NODE_FUNCTION_MULTIARCH (l2_gbp_id_2_sclass_node, l2_gbp_id_2_sclass);
287 VLIB_NODE_FUNCTION_MULTIARCH (l2_gbp_sclass_2_id_node, l2_gbp_sclass_2_id);
288
289 VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_id_2_sclass_node, ip4_gbp_id_2_sclass);
290 VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_sclass_2_id_node, ip4_gbp_sclass_2_id);
291 VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_id_2_sclass_node, ip6_gbp_id_2_sclass);
292 VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_sclass_2_id_node, ip6_gbp_sclass_2_id);
293
294 VNET_FEATURE_INIT (ip4_gbp_sclass_2_id_feat, static) =
295 {
296   .arc_name = "ip4-unicast",
297   .node_name = "ip4-gbp-sclass-2-id",
298   .runs_before = VNET_FEATURES ("gbp-learn-ip4"),
299 };
300 VNET_FEATURE_INIT (ip6_gbp_sclass_2_id_feat, static) =
301 {
302   .arc_name = "ip6-unicast",
303   .node_name = "ip6-gbp-sclass-2-id",
304   .runs_before = VNET_FEATURES ("gbp-learn-ip6"),
305 };
306 VNET_FEATURE_INIT (ip4_gbp_id_2_sclass_feat, static) =
307 {
308   .arc_name = "ip4-output",
309   .node_name = "ip4-gbp-id-2-sclass",
310 };
311 VNET_FEATURE_INIT (ip6_gbp_id_2_sclass_feat, static) =
312 {
313   .arc_name = "ip6-output",
314   .node_name = "ip6-gbp-id-2-sclass",
315 };
316 /* *INDENT-ON* */
317
318 void
319 gbp_sclass_enable_l2 (u32 sw_if_index)
320 {
321   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SCLASS_2_ID, 1);
322   l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_ID_2_SCLASS, 1);
323 }
324
325 void
326 gbp_sclass_disable_l2 (u32 sw_if_index)
327 {
328   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SCLASS_2_ID, 0);
329   l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_ID_2_SCLASS, 0);
330 }
331
332 void
333 gbp_sclass_enable_ip (u32 sw_if_index)
334 {
335   vnet_feature_enable_disable ("ip4-unicast",
336                                "ip4-gbp-sclass-2-id", sw_if_index, 1, 0, 0);
337   vnet_feature_enable_disable ("ip6-unicast",
338                                "ip6-gbp-sclass-2-id", sw_if_index, 1, 0, 0);
339   vnet_feature_enable_disable ("ip4-output",
340                                "ip4-gbp-id-2-sclass", sw_if_index, 1, 0, 0);
341   vnet_feature_enable_disable ("ip6-output",
342                                "ip6-gbp-id-2-sclass", sw_if_index, 1, 0, 0);
343 }
344
345 void
346 gbp_sclass_disable_ip (u32 sw_if_index)
347 {
348   vnet_feature_enable_disable ("ip4-unicast",
349                                "ip4-gbp-sclass-2-id", sw_if_index, 0, 0, 0);
350   vnet_feature_enable_disable ("ip6-unicast",
351                                "ip6-gbp-sclass-2-id", sw_if_index, 0, 0, 0);
352   vnet_feature_enable_disable ("ip4-output",
353                                "ip4-gbp-id-2-sclass", sw_if_index, 0, 0, 0);
354   vnet_feature_enable_disable ("ip6-output",
355                                "ip6-gbp-id-2-sclass", sw_if_index, 0, 0, 0);
356 }
357
358 static clib_error_t *
359 gbp_sclass_init (vlib_main_t * vm)
360 {
361   gbp_sclass_main_t *glm = &gbp_sclass_main;
362
363   /* Initialize the feature next-node indices */
364   feat_bitmap_init_next_nodes (vm,
365                                l2_gbp_sclass_2_id_node.index,
366                                L2INPUT_N_FEAT,
367                                l2input_get_feat_names (),
368                                glm->gel_l2_input_feat_next);
369   feat_bitmap_init_next_nodes (vm,
370                                l2_gbp_id_2_sclass_node.index,
371                                L2OUTPUT_N_FEAT,
372                                l2output_get_feat_names (),
373                                glm->gel_l2_output_feat_next);
374
375   return (NULL);
376 }
377
378 VLIB_INIT_FUNCTION (gbp_sclass_init);
379
380 /*
381  * fd.io coding-style-patch-verification: ON
382  *
383  * Local Variables:
384  * eval: (c-set-style "gnu")
385  * End:
386  */