2 * gbp.h : Group Based Policy
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
31 * per-packet trace data
33 typedef struct gbp_classify_trace_t_
35 /* per-pkt trace data */
37 } gbp_classify_trace_t;
40 * determine the SRC EPG form the input port
43 gbp_classify_inline (vlib_main_t * vm,
44 vlib_node_runtime_t * node,
46 gbp_src_classify_type_t type, dpo_proto_t dproto)
48 gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
49 u32 n_left_from, *from, *to_next;
53 n_left_from = frame->n_vectors;
54 from = vlib_frame_vector_args (frame);
56 while (n_left_from > 0)
60 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
62 while (n_left_from > 0 && n_left_to_next > 0)
64 u32 next0, bi0, src_epg, sw_if_index0;
65 const gbp_endpoint_t *ge0;
75 b0 = vlib_get_buffer (vm, bi0);
77 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
78 vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_NONE;
80 if (GBP_SRC_CLASSIFY_NULL == type)
82 src_epg = EPG_INVALID;
84 vnet_l2_feature_next (b0, gscm->l2_input_feat_next[type],
85 L2INPUT_FEAT_GBP_NULL_CLASSIFY);
89 if (DPO_PROTO_ETHERNET == dproto)
91 const ethernet_header_t *h0;
93 h0 = vlib_buffer_get_current (b0);
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);
100 else if (DPO_PROTO_IP4 == dproto)
102 const ip4_header_t *h0;
104 h0 = vlib_buffer_get_current (b0);
106 ge0 = gbp_endpoint_find_ip4
108 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
113 * Go straight to looukp, do not pass go, do not collect $200
117 else if (DPO_PROTO_IP6 == dproto)
119 const ip6_header_t *h0;
121 h0 = vlib_buffer_get_current (b0);
123 ge0 = gbp_endpoint_find_ip6
125 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6,
130 * Go straight to lookup, do not pass go, do not collect $200
141 if (PREDICT_TRUE (NULL != ge0))
142 src_epg = ge0->ge_fwd.gef_epg_id;
144 src_epg = EPG_INVALID;
147 vnet_buffer2 (b0)->gbp.src_epg = src_epg;
149 if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
151 gbp_classify_trace_t *t =
152 vlib_add_trace (vm, node, b0, sizeof (*t));
153 t->src_epg = src_epg;
156 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
157 to_next, n_left_to_next,
161 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
164 return frame->n_vectors;
167 VLIB_NODE_FN (gbp_src_classify_node) (vlib_main_t * vm,
168 vlib_node_runtime_t * node,
169 vlib_frame_t * frame)
171 return (gbp_classify_inline (vm, node, frame,
172 GBP_SRC_CLASSIFY_PORT, DPO_PROTO_ETHERNET));
175 VLIB_NODE_FN (gbp_null_classify_node) (vlib_main_t * vm,
176 vlib_node_runtime_t * node,
177 vlib_frame_t * frame)
179 return (gbp_classify_inline (vm, node, frame,
180 GBP_SRC_CLASSIFY_NULL, DPO_PROTO_ETHERNET));
183 VLIB_NODE_FN (gbp_ip4_src_classify_node) (vlib_main_t * vm,
184 vlib_node_runtime_t * node,
185 vlib_frame_t * frame)
187 return (gbp_classify_inline (vm, node, frame,
188 GBP_SRC_CLASSIFY_PORT, DPO_PROTO_IP4));
191 VLIB_NODE_FN (gbp_ip6_src_classify_node) (vlib_main_t * vm,
192 vlib_node_runtime_t * node,
193 vlib_frame_t * frame)
195 return (gbp_classify_inline (vm, node, frame,
196 GBP_SRC_CLASSIFY_PORT, DPO_PROTO_IP6));
200 /* packet trace format function */
202 format_gbp_classify_trace (u8 * s, va_list * args)
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 *);
208 s = format (s, "src-epg:%d", t->src_epg);
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,
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,
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,
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,
260 VNET_FEATURE_INIT (gbp_ip4_src_classify_feat_node, static) =
262 .arc_name = "ip4-unicast",
263 .node_name = "ip4-gbp-src-classify",
264 .runs_before = VNET_FEATURES ("nat44-out2in"),
266 VNET_FEATURE_INIT (gbp_ip6_src_classify_feat_node, static) =
268 .arc_name = "ip6-unicast",
269 .node_name = "ip6-gbp-src-classify",
270 .runs_before = VNET_FEATURES ("nat66-out2in"),
275 typedef enum gbp_lpm_classify_next_t_
277 GPB_LPM_CLASSIFY_DROP,
278 } gbp_lpm_classify_next_t;
280 always_inline dpo_proto_t
281 ethertype_to_dpo_proto (const ethernet_header_t * eh0)
283 u16 etype = clib_net_to_host_u16 (eh0->type);
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:
293 ethernet_vlan_header_t *vh0;
295 vh0 = (ethernet_vlan_header_t *) (eh0 + 1);
297 switch (clib_net_to_host_u16 (vh0->type))
299 case ETHERNET_TYPE_IP4:
300 return (DPO_PROTO_IP4);
301 case ETHERNET_TYPE_IP6:
302 return (DPO_PROTO_IP6);
307 return (DPO_PROTO_NONE);
311 * Determine the SRC EPG from a LPM
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)
319 gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
320 u32 n_left_from, *from, *to_next;
324 n_left_from = frame->n_vectors;
325 from = vlib_frame_vector_args (frame);
327 while (n_left_from > 0)
331 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
333 while (n_left_from > 0 && n_left_to_next > 0)
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;
355 next0 = GPB_LPM_CLASSIFY_DROP;
357 b0 = vlib_get_buffer (vm, bi0);
359 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
360 vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_NONE;
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)
368 const ethernet_header_t *eh0;
370 eh0 = vlib_buffer_get_current (b0);
372 dproto = ethertype_to_dpo_proto (eh0);
377 ip4_0 = (vlib_buffer_get_current (b0) +
378 vnet_buffer (b0)->l2.l2_len);
381 ip6_0 = (vlib_buffer_get_current (b0) +
382 vnet_buffer (b0)->l2.l2_len);
385 /* not IP so no LPM classify possible */
386 src_epg0 = EPG_INVALID;
393 gr0 = gbp_recirc_get (sw_if_index0);
394 fib_index0 = gr0->gr_fib_index[dproto];
396 vnet_feature_next (&next0, b0);
400 gx0 = gbp_ext_itf_get (sw_if_index0);
401 fib_index0 = gx0->gx_fib_index[dproto];
403 next0 = vnet_l2_feature_next
404 (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM],
405 L2INPUT_FEAT_GBP_LPM_CLASSIFY);
408 if (DPO_PROTO_IP4 == dproto)
410 lbi0 = ip4_fib_forwarding_lookup (fib_index0,
411 &ip4_0->src_address);
413 else if (DPO_PROTO_IP6 == dproto)
415 lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
416 &ip6_0->src_address);
420 /* not IP so no LPM classify possible */
421 src_epg0 = EPG_INVALID;
424 lb0 = load_balance_get (lbi0);
425 dpo0 = load_balance_get_bucket_i (lb0, 0);
427 if (gbp_policy_dpo_type == dpo0->dpoi_type)
429 gpd0 = gbp_policy_dpo_get (dpo0->dpoi_index);
430 src_epg0 = gpd0->gpd_epg;
434 /* could not classify => drop */
435 src_epg0 = EPG_INVALID;
436 next0 = GPB_LPM_CLASSIFY_DROP;
440 vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
442 if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
444 gbp_classify_trace_t *t =
445 vlib_add_trace (vm, node, b0, sizeof (*t));
446 t->src_epg = src_epg0;
449 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
450 to_next, n_left_to_next,
454 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
457 return frame->n_vectors;
460 VLIB_NODE_FN (gbp_ip4_lpm_classify_node) (vlib_main_t * vm,
461 vlib_node_runtime_t * node,
462 vlib_frame_t * frame)
464 return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP4, 1));
467 VLIB_NODE_FN (gbp_ip6_lpm_classify_node) (vlib_main_t * vm,
468 vlib_node_runtime_t * node,
469 vlib_frame_t * frame)
471 return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP6, 1));
474 VLIB_NODE_FN (gbp_l2_lpm_classify_node) (vlib_main_t * vm,
475 vlib_node_runtime_t * node,
476 vlib_frame_t * frame)
478 return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
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,
491 [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
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,
504 [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
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,
517 [GPB_LPM_CLASSIFY_DROP] = "error-drop"
521 VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
523 .arc_name = "ip4-unicast",
524 .node_name = "ip4-gbp-lpm-classify",
525 .runs_before = VNET_FEATURES ("nat44-out2in"),
527 VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
529 .arc_name = "ip6-unicast",
530 .node_name = "ip6-gbp-lpm-classify",
531 .runs_before = VNET_FEATURES ("nat66-out2in"),
537 * fd.io coding-style-patch-verification: ON
540 * eval: (c-set-style "gnu")