GBP Endpoint Learning
[vpp.git] / src / plugins / gbp / gbp_policy.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
18 #include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
19
20 /**
21  * Grouping of global data for the GBP source EPG classification feature
22  */
23 typedef struct gbp_policy_main_t_
24 {
25   /**
26    * Next nodes for L2 output features
27    */
28   u32 l2_output_feat_next[2][32];
29 } gbp_policy_main_t;
30
31 static gbp_policy_main_t gbp_policy_main;
32
33 #define foreach_gbp_policy                      \
34   _(DENY,    "deny")
35
36 typedef enum
37 {
38 #define _(sym,str) GBP_ERROR_##sym,
39   foreach_gbp_policy
40 #undef _
41     GBP_POLICY_N_ERROR,
42 } gbp_policy_error_t;
43
44 static char *gbp_policy_error_strings[] = {
45 #define _(sym,string) string,
46   foreach_gbp_policy
47 #undef _
48 };
49
50 typedef enum
51 {
52 #define _(sym,str) GBP_POLICY_NEXT_##sym,
53   foreach_gbp_policy
54 #undef _
55     GBP_POLICY_N_NEXT,
56 } gbp_policy_next_t;
57
58 /**
59  * per-packet trace data
60  */
61 typedef struct gbp_policy_trace_t_
62 {
63   /* per-pkt trace data */
64   u32 src_epg;
65   u32 dst_epg;
66   u32 acl_index;
67   u32 allowed;
68 } gbp_policy_trace_t;
69
70 static uword
71 gbp_policy_inline (vlib_main_t * vm,
72                    vlib_node_runtime_t * node,
73                    vlib_frame_t * frame, u8 is_port_based)
74 {
75   gbp_main_t *gm = &gbp_main;
76   gbp_policy_main_t *gpm = &gbp_policy_main;
77   u32 n_left_from, *from, *to_next;
78   u32 next_index;
79
80   next_index = 0;
81   n_left_from = frame->n_vectors;
82   from = vlib_frame_vector_args (frame);
83
84   while (n_left_from > 0)
85     {
86       u32 n_left_to_next;
87
88       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
89
90       while (n_left_from > 0 && n_left_to_next > 0)
91         {
92           const ethernet_header_t *h0;
93           const gbp_endpoint_t *ge0;
94           gbp_policy_next_t next0;
95           gbp_contract_key_t key0;
96           gbp_contract_value_t value0 = {
97             .as_u64 = ~0,
98           };
99           u32 bi0, sw_if_index0;
100           vlib_buffer_t *b0;
101
102           next0 = GBP_POLICY_NEXT_DENY;
103           bi0 = from[0];
104           to_next[0] = bi0;
105           from += 1;
106           to_next += 1;
107           n_left_from -= 1;
108           n_left_to_next -= 1;
109
110           b0 = vlib_get_buffer (vm, bi0);
111           h0 = vlib_buffer_get_current (b0);
112           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
113
114           /*
115            * If the A0bit is set then policy has already been applied
116            * and we skip enforcement here.
117            */
118           if (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A)
119             {
120               next0 = vnet_l2_feature_next (b0,
121                                             gpm->l2_output_feat_next
122                                             [is_port_based],
123                                             (is_port_based ?
124                                              L2OUTPUT_FEAT_GBP_POLICY_PORT :
125                                              L2OUTPUT_FEAT_GBP_POLICY_MAC));
126               key0.as_u32 = ~0;
127               goto trace;
128             }
129           /*
130            * determine the src and dst EPG
131            */
132           if (is_port_based)
133             ge0 = gbp_endpoint_find_itf (sw_if_index0);
134           else
135             ge0 = gbp_endpoint_find_mac (h0->dst_address,
136                                          vnet_buffer (b0)->l2.bd_index);
137
138           if (NULL != ge0)
139             key0.gck_dst = ge0->ge_epg_id;
140           else
141             /* If you cannot determine the destination EP then drop */
142             goto trace;
143
144           key0.gck_src = vnet_buffer2 (b0)->gbp.src_epg;
145
146           if (EPG_INVALID != key0.gck_src)
147             {
148               if (PREDICT_FALSE (key0.gck_src == key0.gck_dst))
149                 {
150                   /*
151                    * intra-epg allowed
152                    */
153                   next0 =
154                     vnet_l2_feature_next (b0,
155                                           gpm->l2_output_feat_next
156                                           [is_port_based],
157                                           (is_port_based ?
158                                            L2OUTPUT_FEAT_GBP_POLICY_PORT :
159                                            L2OUTPUT_FEAT_GBP_POLICY_MAC));
160                   vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
161                 }
162               else
163                 {
164                   value0.as_u64 = gbp_acl_lookup (&key0);
165
166                   if (~0 != value0.gc_lc_index)
167                     {
168                       fa_5tuple_opaque_t pkt_5tuple0;
169                       u8 action0 = 0;
170                       u32 acl_pos_p0, acl_match_p0;
171                       u32 rule_match_p0, trace_bitmap0;
172                       u8 *h0, l2_len0;
173                       u16 ether_type0;
174                       u8 is_ip60 = 0;
175
176                       l2_len0 = vnet_buffer (b0)->l2.l2_len;
177                       h0 = vlib_buffer_get_current (b0);
178
179                       ether_type0 =
180                         clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
181
182                       is_ip60 = (ether_type0 == ETHERNET_TYPE_IP6) ? 1 : 0;
183                       /*
184                        * tests against the ACL
185                        */
186                       acl_plugin_fill_5tuple_inline (gm->
187                                                      acl_plugin.p_acl_main,
188                                                      value0.gc_lc_index, b0,
189                                                      is_ip60,
190                                                      /* is_input */ 0,
191                                                      /* is_l2_path */ 1,
192                                                      &pkt_5tuple0);
193                       acl_plugin_match_5tuple_inline (gm->
194                                                       acl_plugin.p_acl_main,
195                                                       value0.gc_lc_index,
196                                                       &pkt_5tuple0, is_ip60,
197                                                       &action0, &acl_pos_p0,
198                                                       &acl_match_p0,
199                                                       &rule_match_p0,
200                                                       &trace_bitmap0);
201
202                       if (action0 > 0)
203                         {
204                           vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
205
206                           next0 =
207                             vnet_l2_feature_next (b0,
208                                                   gpm->l2_output_feat_next
209                                                   [is_port_based],
210                                                   (is_port_based ?
211                                                    L2OUTPUT_FEAT_GBP_POLICY_PORT
212                                                    :
213                                                    L2OUTPUT_FEAT_GBP_POLICY_MAC));
214                           ;
215                         }
216                     }
217                 }
218             }
219           else
220             {
221               /*
222                * the src EPG is not set when the packet arrives on an EPG
223                * uplink interface and we do not need to apply policy
224                */
225               next0 =
226                 vnet_l2_feature_next (b0,
227                                       gpm->l2_output_feat_next[is_port_based],
228                                       (is_port_based ?
229                                        L2OUTPUT_FEAT_GBP_POLICY_PORT :
230                                        L2OUTPUT_FEAT_GBP_POLICY_MAC));
231             }
232
233         trace:
234           if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
235             {
236               gbp_policy_trace_t *t =
237                 vlib_add_trace (vm, node, b0, sizeof (*t));
238               t->src_epg = key0.gck_src;
239               t->dst_epg = key0.gck_dst;
240               t->acl_index = value0.gc_acl_index;
241               t->allowed = (next0 != GBP_POLICY_NEXT_DENY);
242             }
243
244           /* verify speculative enqueue, maybe switch current next frame */
245           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
246                                            to_next, n_left_to_next,
247                                            bi0, next0);
248         }
249
250       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
251     }
252
253   return frame->n_vectors;
254 }
255
256 static uword
257 gbp_policy_port (vlib_main_t * vm,
258                  vlib_node_runtime_t * node, vlib_frame_t * frame)
259 {
260   return (gbp_policy_inline (vm, node, frame, 1));
261 }
262
263 static uword
264 gbp_policy_mac (vlib_main_t * vm,
265                 vlib_node_runtime_t * node, vlib_frame_t * frame)
266 {
267   return (gbp_policy_inline (vm, node, frame, 0));
268 }
269
270 /* packet trace format function */
271 static u8 *
272 format_gbp_policy_trace (u8 * s, va_list * args)
273 {
274   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
275   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
276   gbp_policy_trace_t *t = va_arg (*args, gbp_policy_trace_t *);
277
278   s =
279     format (s, "src:%d, dst:%d, acl:%d allowed:%d",
280             t->src_epg, t->dst_epg, t->acl_index, t->allowed);
281
282   return s;
283 }
284
285 /* *INDENT-OFF* */
286 VLIB_REGISTER_NODE (gbp_policy_port_node) = {
287   .function = gbp_policy_port,
288   .name = "gbp-policy-port",
289   .vector_size = sizeof (u32),
290   .format_trace = format_gbp_policy_trace,
291   .type = VLIB_NODE_TYPE_INTERNAL,
292
293   .n_errors = ARRAY_LEN(gbp_policy_error_strings),
294   .error_strings = gbp_policy_error_strings,
295
296   .n_next_nodes = GBP_POLICY_N_NEXT,
297
298   .next_nodes = {
299     [GBP_POLICY_NEXT_DENY] = "error-drop",
300   },
301 };
302
303 VLIB_NODE_FUNCTION_MULTIARCH (gbp_policy_port_node, gbp_policy_port);
304
305 VLIB_REGISTER_NODE (gbp_policy_mac_node) = {
306   .function = gbp_policy_mac,
307   .name = "gbp-policy-mac",
308   .vector_size = sizeof (u32),
309   .format_trace = format_gbp_policy_trace,
310   .type = VLIB_NODE_TYPE_INTERNAL,
311
312   .n_errors = ARRAY_LEN(gbp_policy_error_strings),
313   .error_strings = gbp_policy_error_strings,
314
315   .n_next_nodes = GBP_POLICY_N_NEXT,
316
317   .next_nodes = {
318     [GBP_POLICY_NEXT_DENY] = "error-drop",
319   },
320 };
321
322 VLIB_NODE_FUNCTION_MULTIARCH (gbp_policy_mac_node, gbp_policy_mac);
323
324 /* *INDENT-ON* */
325
326 static clib_error_t *
327 gbp_policy_init (vlib_main_t * vm)
328 {
329   gbp_policy_main_t *gpm = &gbp_policy_main;
330   clib_error_t *error = 0;
331
332   /* Initialize the feature next-node indexes */
333   feat_bitmap_init_next_nodes (vm,
334                                gbp_policy_port_node.index,
335                                L2OUTPUT_N_FEAT,
336                                l2output_get_feat_names (),
337                                gpm->l2_output_feat_next[1]);
338   feat_bitmap_init_next_nodes (vm,
339                                gbp_policy_mac_node.index,
340                                L2OUTPUT_N_FEAT,
341                                l2output_get_feat_names (),
342                                gpm->l2_output_feat_next[0]);
343
344   return error;
345 }
346
347 VLIB_INIT_FUNCTION (gbp_policy_init);
348
349 /*
350  * fd.io coding-style-patch-verification: ON
351  *
352  * Local Variables:
353  * eval: (c-set-style "gnu")
354  * End:
355  */