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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vnet/dpo/dvr_dpo.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/ip6_fib.h>
19 #include <vnet/dpo/load_balance.h>
20 #include <vnet/dpo/drop_dpo.h>
21 #include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
23 #include <plugins/gbp/gbp.h>
24 #include <plugins/gbp/gbp_policy_dpo.h>
25 #include <plugins/gbp/gbp_recirc.h>
30 static gbp_policy_dpo_t *gbp_policy_dpo_pool;
33 * DPO type registered for these GBP FWD
35 static dpo_type_t gbp_policy_dpo_type;
37 static inline gbp_policy_dpo_t *
38 gbp_policy_dpo_get_i (index_t index)
40 return (pool_elt_at_index (gbp_policy_dpo_pool, index));
44 gbp_policy_dpo_get (index_t index)
46 return (gbp_policy_dpo_get_i (index));
49 static gbp_policy_dpo_t *
50 gbp_policy_dpo_alloc (void)
52 gbp_policy_dpo_t *gpd;
54 pool_get_zero (gbp_policy_dpo_pool, gpd);
59 static inline gbp_policy_dpo_t *
60 gbp_policy_dpo_get_from_dpo (const dpo_id_t * dpo)
62 ASSERT (gbp_policy_dpo_type == dpo->dpoi_type);
64 return (gbp_policy_dpo_get_i (dpo->dpoi_index));
68 gbp_policy_dpo_get_index (gbp_policy_dpo_t * gpd)
70 return (gpd - gbp_policy_dpo_pool);
74 gbp_policy_dpo_lock (dpo_id_t * dpo)
76 gbp_policy_dpo_t *gpd;
78 gpd = gbp_policy_dpo_get_from_dpo (dpo);
83 gbp_policy_dpo_unlock (dpo_id_t * dpo)
85 gbp_policy_dpo_t *gpd;
87 gpd = gbp_policy_dpo_get_from_dpo (dpo);
90 if (0 == gpd->gpd_locks)
92 dpo_reset (&gpd->gpd_dpo);
93 pool_put (gbp_policy_dpo_pool, gpd);
98 gbp_policy_dpo_get_urpf (const dpo_id_t * dpo)
100 gbp_policy_dpo_t *gpd;
102 gpd = gbp_policy_dpo_get_from_dpo (dpo);
104 return (gpd->gpd_sw_if_index);
108 gbp_policy_dpo_add_or_lock (dpo_proto_t dproto,
109 epg_id_t epg, u32 sw_if_index, dpo_id_t * dpo)
111 gbp_policy_dpo_t *gpd;
112 dpo_id_t parent = DPO_INVALID;
114 gpd = gbp_policy_dpo_alloc ();
116 gpd->gpd_proto = dproto;
117 gpd->gpd_sw_if_index = sw_if_index;
120 if (~0 != sw_if_index)
123 * stack on the DVR DPO for the output interface
125 dvr_dpo_add_or_lock (sw_if_index, dproto, &parent);
129 dpo_copy (&parent, drop_dpo_get (dproto));
132 dpo_stack (gbp_policy_dpo_type, dproto, &gpd->gpd_dpo, &parent);
133 dpo_set (dpo, gbp_policy_dpo_type, dproto, gbp_policy_dpo_get_index (gpd));
137 format_gbp_policy_dpo (u8 * s, va_list * ap)
139 index_t index = va_arg (*ap, index_t);
140 u32 indent = va_arg (*ap, u32);
141 gbp_policy_dpo_t *gpd = gbp_policy_dpo_get_i (index);
142 vnet_main_t *vnm = vnet_get_main ();
144 s = format (s, "gbp-policy-dpo: %U, epg:%d out:%U",
145 format_dpo_proto, gpd->gpd_proto,
147 format_vnet_sw_if_index_name, vnm, gpd->gpd_sw_if_index);
148 s = format (s, "\n%U", format_white_space, indent + 2);
149 s = format (s, "%U", format_dpo_id, &gpd->gpd_dpo, indent + 4);
155 * Interpose a policy DPO
158 gbp_policy_dpo_interpose (const dpo_id_t * original,
159 const dpo_id_t * parent, dpo_id_t * clone)
161 gbp_policy_dpo_t *gpd, *gpd_clone;
163 gpd_clone = gbp_policy_dpo_alloc ();
164 gpd = gbp_policy_dpo_get (original->dpoi_index);
166 gpd_clone->gpd_proto = gpd->gpd_proto;
167 gpd_clone->gpd_epg = gpd->gpd_epg;
168 gpd_clone->gpd_sw_if_index = gpd->gpd_sw_if_index;
170 dpo_stack (gbp_policy_dpo_type,
171 gpd_clone->gpd_proto, &gpd_clone->gpd_dpo, parent);
175 gpd_clone->gpd_proto, gbp_policy_dpo_get_index (gpd_clone));
178 const static dpo_vft_t gbp_policy_dpo_vft = {
179 .dv_lock = gbp_policy_dpo_lock,
180 .dv_unlock = gbp_policy_dpo_unlock,
181 .dv_format = format_gbp_policy_dpo,
182 .dv_get_urpf = gbp_policy_dpo_get_urpf,
183 .dv_mk_interpose = gbp_policy_dpo_interpose,
187 * @brief The per-protocol VLIB graph nodes that are assigned to a glean
190 * this means that these graph nodes are ones from which a glean is the
191 * parent object in the DPO-graph.
193 const static char *const gbp_policy_dpo_ip4_nodes[] = {
194 "ip4-gbp-policy-dpo",
198 const static char *const gbp_policy_dpo_ip6_nodes[] = {
199 "ip6-gbp-policy-dpo",
203 const static char *const *const gbp_policy_dpo_nodes[DPO_PROTO_NUM] = {
204 [DPO_PROTO_IP4] = gbp_policy_dpo_ip4_nodes,
205 [DPO_PROTO_IP6] = gbp_policy_dpo_ip6_nodes,
209 gbp_policy_dpo_get_type (void)
211 return (gbp_policy_dpo_type);
214 static clib_error_t *
215 gbp_policy_dpo_module_init (vlib_main_t * vm)
217 gbp_policy_dpo_type = dpo_register_new_type (&gbp_policy_dpo_vft,
218 gbp_policy_dpo_nodes);
223 VLIB_INIT_FUNCTION (gbp_policy_dpo_module_init);
225 typedef struct gbp_policy_dpo_trace_t_
231 } gbp_policy_dpo_trace_t;
240 gbp_policy_dpo_inline (vlib_main_t * vm,
241 vlib_node_runtime_t * node,
242 vlib_frame_t * from_frame, u8 is_ip6)
244 gbp_main_t *gm = &gbp_main;
245 u32 n_left_from, next_index, *from, *to_next;
247 from = vlib_frame_vector_args (from_frame);
248 n_left_from = from_frame->n_vectors;
250 next_index = node->cached_next_index;
252 while (n_left_from > 0)
256 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
258 while (n_left_from > 0 && n_left_to_next > 0)
260 const gbp_policy_dpo_t *gpd0;
262 gbp_contract_key_t key0;
263 gbp_contract_value_t value0 = {
274 next0 = GBP_POLICY_DROP;
276 b0 = vlib_get_buffer (vm, bi0);
279 gbp_policy_dpo_get_i (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
280 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = gpd0->gpd_dpo.dpoi_index;
282 if (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A)
284 next0 = gpd0->gpd_dpo.dpoi_next_node;
289 key0.gck_src = vnet_buffer2 (b0)->gbp.src_epg;
290 key0.gck_dst = gpd0->gpd_epg;
292 if (EPG_INVALID != key0.gck_src)
294 if (PREDICT_FALSE (key0.gck_src == key0.gck_dst))
299 next0 = gpd0->gpd_dpo.dpoi_next_node;
300 vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
304 value0.as_u64 = gbp_acl_lookup (&key0);
306 if (~0 != value0.gc_lc_index)
308 fa_5tuple_opaque_t pkt_5tuple0;
310 u32 acl_pos_p0, acl_match_p0;
311 u32 rule_match_p0, trace_bitmap0;
313 * tests against the ACL
315 acl_plugin_fill_5tuple_inline (gm->
316 acl_plugin.p_acl_main,
317 value0.gc_lc_index, b0,
322 acl_plugin_match_5tuple_inline (gm->
323 acl_plugin.p_acl_main,
325 &pkt_5tuple0, is_ip6,
326 &action0, &acl_pos_p0,
333 vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
334 next0 = gpd0->gpd_dpo.dpoi_next_node;
342 * the src EPG is not set when the packet arrives on an EPG
343 * uplink interface and we do not need to apply policy
345 next0 = gpd0->gpd_dpo.dpoi_next_node;
348 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
350 gbp_policy_dpo_trace_t *tr;
352 tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
353 tr->src_epg = key0.gck_src;
354 tr->dst_epg = key0.gck_dst;
355 tr->acl_index = value0.gc_acl_index;
356 tr->a_bit = vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A;
359 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
360 n_left_to_next, bi0, next0);
362 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
364 return from_frame->n_vectors;
368 format_gbp_policy_dpo_trace (u8 * s, va_list * args)
370 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
371 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
372 gbp_policy_dpo_trace_t *t = va_arg (*args, gbp_policy_dpo_trace_t *);
374 s = format (s, " src-epg:%d dst-epg:%d acl-index:%d a-bit:%d",
375 t->src_epg, t->dst_epg, t->acl_index, t->a_bit);
381 ip4_gbp_policy_dpo (vlib_main_t * vm,
382 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
384 return (gbp_policy_dpo_inline (vm, node, from_frame, 0));
388 ip6_gbp_policy_dpo (vlib_main_t * vm,
389 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
391 return (gbp_policy_dpo_inline (vm, node, from_frame, 1));
395 VLIB_REGISTER_NODE (ip4_gbp_policy_dpo_node) = {
396 .function = ip4_gbp_policy_dpo,
397 .name = "ip4-gbp-policy-dpo",
398 .vector_size = sizeof (u32),
399 .format_trace = format_gbp_policy_dpo_trace,
400 .n_next_nodes = GBP_POLICY_N_NEXT,
403 [GBP_POLICY_DROP] = "ip4-drop",
406 VLIB_REGISTER_NODE (ip6_gbp_policy_dpo_node) = {
407 .function = ip6_gbp_policy_dpo,
408 .name = "ip6-gbp-policy-dpo",
409 .vector_size = sizeof (u32),
410 .format_trace = format_gbp_policy_dpo_trace,
411 .n_next_nodes = GBP_POLICY_N_NEXT,
414 [GBP_POLICY_DROP] = "ip6-drop",
418 VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_policy_dpo_node, ip4_gbp_policy_dpo)
419 VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_policy_dpo_node, ip6_gbp_policy_dpo)
423 * per-packet trace data
425 typedef struct gbp_classify_trace_t_
427 /* per-pkt trace data */
429 } gbp_classify_trace_t;
431 typedef enum gbp_lpm_classify_next_t_
433 GPB_LPM_CLASSIFY_DROP,
434 } gbp_lpm_classify_next_t;
437 * Determine the SRC EPG from a LPM
440 gbp_lpm_classify_inline (vlib_main_t * vm,
441 vlib_node_runtime_t * node,
442 vlib_frame_t * frame, fib_protocol_t fproto)
444 u32 n_left_from, *from, *to_next;
448 n_left_from = frame->n_vectors;
449 from = vlib_frame_vector_args (frame);
451 while (n_left_from > 0)
455 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
457 while (n_left_from > 0 && n_left_to_next > 0)
459 u32 bi0, sw_if_index0, fib_index0, lbi0;
460 gbp_lpm_classify_next_t next0;
461 const gbp_policy_dpo_t *gpd0;
462 const gbp_recirc_t *gr0;
463 const dpo_id_t *dpo0;
476 next0 = GPB_LPM_CLASSIFY_DROP;
478 b0 = vlib_get_buffer (vm, bi0);
480 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
481 gr0 = gbp_recirc_get (sw_if_index0);
482 fib_index0 = gr0->gr_fib_index[fproto];
484 if (FIB_PROTOCOL_IP4 == fproto)
486 ip4_0 = vlib_buffer_get_current (b0);
487 lbi0 = ip4_fib_forwarding_lookup (fib_index0,
488 &ip4_0->src_address);
492 ip6_0 = vlib_buffer_get_current (b0);
493 lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
494 &ip6_0->src_address);
497 lb0 = load_balance_get (lbi0);
498 dpo0 = load_balance_get_bucket_i (lb0, 0);
500 if (gbp_policy_dpo_type == dpo0->dpoi_type)
502 gpd0 = gbp_policy_dpo_get_i (dpo0->dpoi_index);
503 src_epg0 = gpd0->gpd_epg;
504 vnet_feature_next (&next0, b0);
508 /* could not classify => drop */
512 vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
514 if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
516 gbp_classify_trace_t *t =
517 vlib_add_trace (vm, node, b0, sizeof (*t));
518 t->src_epg = src_epg0;
521 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
522 to_next, n_left_to_next,
526 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
529 return frame->n_vectors;
533 gbp_ip4_lpm_classify (vlib_main_t * vm,
534 vlib_node_runtime_t * node, vlib_frame_t * frame)
536 return (gbp_lpm_classify_inline (vm, node, frame, FIB_PROTOCOL_IP4));
540 gbp_ip6_lpm_classify (vlib_main_t * vm,
541 vlib_node_runtime_t * node, vlib_frame_t * frame)
543 return (gbp_lpm_classify_inline (vm, node, frame, FIB_PROTOCOL_IP6));
546 /* packet trace format function */
548 format_gbp_classify_trace (u8 * s, va_list * args)
550 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
551 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
552 gbp_classify_trace_t *t = va_arg (*args, gbp_classify_trace_t *);
554 s = format (s, "src-epg:%d", t->src_epg);
560 VLIB_REGISTER_NODE (gbp_ip4_lpm_classify_node) = {
561 .function = gbp_ip4_lpm_classify,
562 .name = "ip4-gbp-lpm-classify",
563 .vector_size = sizeof (u32),
564 .format_trace = format_gbp_classify_trace,
565 .type = VLIB_NODE_TYPE_INTERNAL,
570 [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
574 VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip4_lpm_classify_node, gbp_ip4_lpm_classify);
576 VLIB_REGISTER_NODE (gbp_ip6_lpm_classify_node) = {
577 .function = gbp_ip6_lpm_classify,
578 .name = "ip6-gbp-lpm-classify",
579 .vector_size = sizeof (u32),
580 .format_trace = format_gbp_classify_trace,
581 .type = VLIB_NODE_TYPE_INTERNAL,
586 [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
590 VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip6_lpm_classify_node, gbp_ip6_lpm_classify);
592 VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
594 .arc_name = "ip4-unicast",
595 .node_name = "ip4-gbp-lpm-classify",
596 .runs_before = VNET_FEATURES ("nat44-out2in"),
598 VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
600 .arc_name = "ip6-unicast",
601 .node_name = "ip6-gbp-lpm-classify",
602 .runs_before = VNET_FEATURES ("nat66-out2in"),
608 * fd.io coding-style-patch-verification: ON
611 * eval: (c-set-style "gnu")