FD.io VPP  v21.01.1
Vector Packet Processing
gbp_policy_dpo.c
Go to the documentation of this file.
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 <vnet/dpo/dvr_dpo.h>
17 #include <vnet/dpo/drop_dpo.h>
20 
21 #include <plugins/gbp/gbp.h>
22 #include <plugins/gbp/gbp_policy.h>
24 #include <plugins/gbp/gbp_recirc.h>
26 
27 #ifndef CLIB_MARCH_VARIANT
28 /**
29  * DPO pool
30  */
32 
33 /**
34  * DPO type registered for these GBP FWD
35  */
37 
38 static gbp_policy_dpo_t *
40 {
41  gbp_policy_dpo_t *gpd;
42 
43  pool_get_aligned_zero (gbp_policy_dpo_pool, gpd, CLIB_CACHE_LINE_BYTES);
44 
45  return (gpd);
46 }
47 
48 static inline gbp_policy_dpo_t *
50 {
52 
53  return (gbp_policy_dpo_get (dpo->dpoi_index));
54 }
55 
56 static inline index_t
58 {
59  return (gpd - gbp_policy_dpo_pool);
60 }
61 
62 static void
64 {
65  gbp_policy_dpo_t *gpd;
66 
67  gpd = gbp_policy_dpo_get_from_dpo (dpo);
68  gpd->gpd_locks++;
69 }
70 
71 static void
73 {
74  gbp_policy_dpo_t *gpd;
75 
76  gpd = gbp_policy_dpo_get_from_dpo (dpo);
77  gpd->gpd_locks--;
78 
79  if (0 == gpd->gpd_locks)
80  {
81  dpo_reset (&gpd->gpd_dpo);
82  pool_put (gbp_policy_dpo_pool, gpd);
83  }
84 }
85 
86 static u32
88 {
89  gbp_policy_dpo_t *gpd;
90 
91  gpd = gbp_policy_dpo_get_from_dpo (dpo);
92 
93  return (gpd->gpd_sw_if_index);
94 }
95 
96 void
100 {
101  gbp_policy_dpo_t *gpd;
102  dpo_id_t parent = DPO_INVALID;
103 
104  gpd = gbp_policy_dpo_alloc ();
105 
106  gpd->gpd_proto = dproto;
108  gpd->gpd_sclass = sclass;
109  gpd->gpd_scope = scope;
110 
111  if (~0 != sw_if_index)
112  {
113  /*
114  * stack on the DVR DPO for the output interface
115  */
116  dvr_dpo_add_or_lock (sw_if_index, dproto, &parent);
117  }
118  else
119  {
120  dpo_copy (&parent, drop_dpo_get (dproto));
121  }
122 
123  dpo_stack (gbp_policy_dpo_type, dproto, &gpd->gpd_dpo, &parent);
125 }
126 
127 u8 *
128 format_gbp_policy_dpo (u8 * s, va_list * ap)
129 {
130  index_t index = va_arg (*ap, index_t);
131  u32 indent = va_arg (*ap, u32);
132  gbp_policy_dpo_t *gpd = gbp_policy_dpo_get (index);
133  vnet_main_t *vnm = vnet_get_main ();
134 
135  s = format (s, "gbp-policy-dpo: %U, scope:%d sclass:%d out:%U",
137  gpd->gpd_scope, (int) gpd->gpd_sclass,
139  s = format (s, "\n%U", format_white_space, indent + 2);
140  s = format (s, "%U", format_dpo_id, &gpd->gpd_dpo, indent + 4);
141 
142  return (s);
143 }
144 
145 /**
146  * Interpose a policy DPO
147  */
148 static void
150  const dpo_id_t * parent, dpo_id_t * clone)
151 {
152  gbp_policy_dpo_t *gpd, *gpd_clone;
153 
154  gpd_clone = gbp_policy_dpo_alloc ();
155  gpd = gbp_policy_dpo_get (original->dpoi_index);
156 
157  gpd_clone->gpd_proto = gpd->gpd_proto;
158  gpd_clone->gpd_scope = gpd->gpd_scope;
159  gpd_clone->gpd_sclass = gpd->gpd_sclass;
160  gpd_clone->gpd_sw_if_index = gpd->gpd_sw_if_index;
161 
162  /*
163  * if no interface is provided, grab one from the parent
164  * on which we stack
165  */
166  if (~0 == gpd_clone->gpd_sw_if_index)
167  gpd_clone->gpd_sw_if_index = dpo_get_urpf (parent);
168 
170  gpd_clone->gpd_proto, &gpd_clone->gpd_dpo, parent);
171 
172  dpo_set (clone,
174  gpd_clone->gpd_proto, gbp_policy_dpo_get_index (gpd_clone));
175 }
176 
177 const static dpo_vft_t gbp_policy_dpo_vft = {
179  .dv_unlock = gbp_policy_dpo_unlock,
180  .dv_format = format_gbp_policy_dpo,
181  .dv_get_urpf = gbp_policy_dpo_get_urpf,
182  .dv_mk_interpose = gbp_policy_dpo_interpose,
183 };
184 
185 /**
186  * @brief The per-protocol VLIB graph nodes that are assigned to a glean
187  * object.
188  *
189  * this means that these graph nodes are ones from which a glean is the
190  * parent object in the DPO-graph.
191  */
192 const static char *const gbp_policy_dpo_ip4_nodes[] = {
193  "ip4-gbp-policy-dpo",
194  NULL,
195 };
196 
197 const static char *const gbp_policy_dpo_ip6_nodes[] = {
198  "ip6-gbp-policy-dpo",
199  NULL,
200 };
201 
202 const static char *const *const gbp_policy_dpo_nodes[DPO_PROTO_NUM] = {
205 };
206 
209 {
210  return (gbp_policy_dpo_type);
211 }
212 
213 static clib_error_t *
215 {
216  gbp_policy_dpo_type = dpo_register_new_type (&gbp_policy_dpo_vft,
218 
219  return (NULL);
220 }
221 
223 #endif /* CLIB_MARCH_VARIANT */
224 
225 typedef enum
226 {
230 
233 {
234  gbp_policy_node_t pnode;
235  const dpo_id_t *dpo;
236  dpo_proto_t dproto;
237 
238  pnode = (is_ip6 ? GBP_POLICY_NODE_IP6 : GBP_POLICY_NODE_IP4);
239  dproto = (is_ip6 ? DPO_PROTO_IP6 : DPO_PROTO_IP4);
240  dpo = &gu->gu_dpo[pnode][dproto];
241 
242  /* The flow hash is still valid as this is a IP packet being switched */
243  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo->dpoi_index;
244 
245  return (dpo->dpoi_next_node);
246 }
247 
251  vlib_frame_t * from_frame, u8 is_ip6)
252 {
253  gbp_main_t *gm = &gbp_main;
254  u32 n_left_from, next_index, *from, *to_next;
255  u32 n_allow_intra, n_allow_a_bit, n_allow_sclass_1;
256 
257  from = vlib_frame_vector_args (from_frame);
258  n_left_from = from_frame->n_vectors;
259  n_allow_intra = n_allow_a_bit = n_allow_sclass_1 = 0;
260 
261  next_index = node->cached_next_index;
262 
263  while (n_left_from > 0)
264  {
265  u32 n_left_to_next;
266 
267  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
268 
269  while (n_left_from > 0 && n_left_to_next > 0)
270  {
271  gbp_rule_action_t action0 = GBP_RULE_DENY;
272  u32 acl_match = ~0, rule_match = ~0;
273  const gbp_policy_dpo_t *gpd0;
275  gbp_contract_key_t key0;
276  vlib_buffer_t *b0;
277  gbp_rule_t *rule0;
278  u32 bi0, next0;
279 
280  bi0 = from[0];
281  to_next[0] = bi0;
282  from += 1;
283  to_next += 1;
284  n_left_from -= 1;
285  n_left_to_next -= 1;
286  next0 = GBP_POLICY_DROP;
287 
288  b0 = vlib_get_buffer (vm, bi0);
289 
290  gpd0 = gbp_policy_dpo_get (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
291  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = gpd0->gpd_dpo.dpoi_index;
292 
293  /*
294  * Reflection check; in and out on an ivxlan tunnel
295  */
297  && (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_R))
298  {
299  goto trace;
300  }
301 
302  if (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A)
303  {
304  next0 = gpd0->gpd_dpo.dpoi_next_node;
305  key0.as_u64 = ~0;
306  n_allow_a_bit++;
307  goto trace;
308  }
309 
310  /* zero out the key to ensure the pad space is clear */
311  key0.as_u64 = 0;
312  key0.gck_src = vnet_buffer2 (b0)->gbp.sclass;
313 
314  if (SCLASS_INVALID == key0.gck_src)
315  {
316  /*
317  * the src EPG is not set when the packet arrives on an EPG
318  * uplink interface and we do not need to apply policy
319  */
320  next0 = gpd0->gpd_dpo.dpoi_next_node;
321  goto trace;
322  }
323 
324  key0.gck_scope = gpd0->gpd_scope;
325  key0.gck_dst = gpd0->gpd_sclass;
326 
327  action0 =
328  gbp_contract_apply (vm, gm, &key0, b0, &rule0, &n_allow_intra,
329  &n_allow_sclass_1, &acl_match, &rule_match,
330  &err0,
331  is_ip6 ? GBP_CONTRACT_APPLY_IP6 :
333  switch (action0)
334  {
335  case GBP_RULE_PERMIT:
336  next0 = gpd0->gpd_dpo.dpoi_next_node;
337  vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
338  break;
339  case GBP_RULE_REDIRECT:
340  next0 = gbp_rule_l3_redirect (rule0, b0, is_ip6);
341  vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
342  break;
343  case GBP_RULE_DENY:
344  next0 = GBP_POLICY_DROP;
345  b0->error = node->errors[err0];
346  break;
347  }
348 
349  trace:
350  gbp_policy_trace (vm, node, b0, &key0, action0, acl_match,
351  rule_match);
352 
353  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
354  n_left_to_next, bi0, next0);
355  }
356  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
357  }
358 
360  GBP_CONTRACT_ERROR_ALLOW_INTRA, n_allow_intra);
362  GBP_CONTRACT_ERROR_ALLOW_A_BIT, n_allow_a_bit);
364  GBP_CONTRACT_ERROR_ALLOW_SCLASS_1,
365  n_allow_sclass_1);
366  return from_frame->n_vectors;
367 }
368 
371  vlib_frame_t * from_frame)
372 {
373  return (gbp_policy_dpo_inline (vm, node, from_frame, 0));
374 }
375 
378  vlib_frame_t * from_frame)
379 {
380  return (gbp_policy_dpo_inline (vm, node, from_frame, 1));
381 }
382 
383 /* *INDENT-OFF* */
385  .name = "ip4-gbp-policy-dpo",
386  .vector_size = sizeof (u32),
387  .format_trace = format_gbp_policy_trace,
388 
390  .error_strings = gbp_contract_error_strings,
391 
392  .n_next_nodes = GBP_POLICY_N_NEXT,
393  .next_nodes =
394  {
395  [GBP_POLICY_DROP] = "ip4-drop",
396  }
397 };
399  .name = "ip6-gbp-policy-dpo",
400  .vector_size = sizeof (u32),
401  .format_trace = format_gbp_policy_trace,
402 
404  .error_strings = gbp_contract_error_strings,
405 
406  .n_next_nodes = GBP_POLICY_N_NEXT,
407  .next_nodes =
408  {
409  [GBP_POLICY_DROP] = "ip6-drop",
410  }
411 };
412 /* *INDENT-ON* */
413 
414 /*
415  * fd.io coding-style-patch-verification: ON
416  *
417  * Local Variables:
418  * eval: (c-set-style "gnu")
419  * End:
420  */
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:411
gbp_policy_next_t
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:899
u16 sclass_t
Definition: gbp_types.h:25
A virtual function table regisitered for a DPO type.
Definition: dpo.h:406
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define vnet_buffer2(b)
Definition: buffer.h:481
The key for an Contract.
Definition: gbp_contract.h:48
void dpo_copy(dpo_id_t *dst, const dpo_id_t *src)
atomic copy a data-plane object.
Definition: dpo.c:262
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
u32 dpo_get_urpf(const dpo_id_t *dpo)
Get a uRPF interface for the DPO.
Definition: dpo.c:387
static_always_inline void gbp_policy_trace(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, const gbp_contract_key_t *key, gbp_rule_action_t action, u32 acl_match, u32 rule_match)
Definition: gbp_policy.h:40
vlib_main_t * vm
Definition: in2out_ed.c:1580
char * gbp_contract_error_strings[]
Definition: gbp_contract.c:27
#define VLIB_NODE_FN(node)
Definition: node.h:203
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
static gbp_policy_dpo_t * gbp_policy_dpo_get_from_dpo(const dpo_id_t *dpo)
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static const char *const gbp_policy_dpo_ip4_nodes[]
The per-protocol VLIB graph nodes that are assigned to a glean object.
const dpo_id_t * drop_dpo_get(dpo_proto_t proto)
Definition: drop_dpo.c:25
gbp_policy_dpo_t * gbp_policy_dpo_pool
DPO pool.
enum dpo_type_t_ dpo_type_t
Common types of data-path objects New types can be dynamically added using dpo_register_new_type() ...
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
static u32 vxlan_gbp_tunnel_by_sw_if_index(u32 sw_if_index)
Definition: vxlan_gbp.h:232
description fragment has unexpected format
Definition: map.api:433
u16 gbp_scope_t
Definition: gbp_types.h:24
static uword gbp_policy_dpo_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, u8 is_ip6)
static gbp_policy_dpo_t * gbp_policy_dpo_alloc(void)
unsigned int u32
Definition: types.h:88
u32 gpd_sw_if_index
output sw_if_index
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, const char *const *const *nodes)
Create and register a new DPO type.
Definition: dpo.c:347
bool is_ip6
Definition: ip.api:43
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
static clib_error_t * gbp_policy_dpo_module_init(vlib_main_t *vm)
dpo_type_t gbp_policy_dpo_get_type(void)
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
u8 * format_gbp_policy_dpo(u8 *s, va_list *ap)
static u32 gbp_policy_dpo_get_urpf(const dpo_id_t *dpo)
The GBP FWD DPO.
static void gbp_policy_dpo_lock(dpo_id_t *dpo)
#define gm
Definition: dlmalloc.c:1219
dpo_type_t dpoi_type
the type
Definition: dpo.h:176
static const char *const gbp_policy_dpo_ip6_nodes[]
sclass_t gck_src
source and destination EPGs for which the ACL applies
Definition: gbp_contract.h:58
void gbp_policy_dpo_add_or_lock(dpo_proto_t dproto, gbp_scope_t scope, sclass_t sclass, u32 sw_if_index, dpo_id_t *dpo)
u16 sclass
Definition: gbp.api:131
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
static_always_inline gbp_rule_action_t gbp_contract_apply(vlib_main_t *vm, gbp_main_t *gm, gbp_contract_key_t *key, vlib_buffer_t *b, gbp_rule_t **rule, u32 *intra, u32 *sclass1, u32 *acl_match, u32 *rule_match, gbp_contract_error_t *err, gbp_contract_apply_type_t type)
Definition: gbp_contract.h:233
static void gbp_policy_dpo_unlock(dpo_id_t *dpo)
#define always_inline
Definition: ipsec.h:28
#define pool_get_aligned_zero(P, E, A)
Allocate an object E from a pool P with alignment A and zero it.
Definition: pool.h:248
#define SCLASS_INVALID
Definition: gbp_types.h:26
u32 node_index
Node index.
Definition: node.h:488
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
gbp_contract_error_t
Definition: gbp_contract.h:34
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:391
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
void dvr_dpo_add_or_lock(u32 sw_if_index, dpo_proto_t dproto, dpo_id_t *dpo)
Definition: dvr_dpo.c:91
gbp_scope_t gpd_scope
sclass scope
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
u16 n_vectors
Definition: node.h:397
vlib_parse_match_function_t rule_match
Definition: parse.h:189
dpo_id_t gu_dpo[GBP_POLICY_N_NODES][FIB_PROTOCOL_IP_MAX]
DPO of the load-balance object used to redirect.
Definition: gbp_contract.h:127
#define ARRAY_LEN(x)
Definition: clib.h:67
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:483
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:186
static void gbp_policy_dpo_interpose(const dpo_id_t *original, const dpo_id_t *parent, dpo_id_t *clone)
Interpose a policy DPO.
sclass_t gpd_sclass
SClass.
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
static const char *const *const gbp_policy_dpo_nodes[DPO_PROTO_NUM]
static gbp_policy_dpo_t * gbp_policy_dpo_get(index_t index)
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:511
#define ASSERT(truth)
gbp_main_t gbp_main
Definition: gbp_api.c:46
u16 gpd_locks
number of locks.
dpo_type_t gbp_policy_dpo_type
DPO type registered for these GBP FWD.
vlib_node_registration_t ip4_gbp_policy_dpo_node
(constructor) VLIB_REGISTER_NODE (ip4_gbp_policy_dpo_node)
u8 * format_gbp_policy_trace(u8 *s, va_list *args)
Definition: gbp_policy.c:24
u8 * format_dpo_id(u8 *s, va_list *args)
Format a DPO_id_t oject.
Definition: dpo.c:148
enum gbp_rule_action_t_ gbp_rule_action_t
Definition: defs.h:47
#define DPO_PROTO_NUM
Definition: dpo.h:70
vl_api_address_t ip
Definition: l2.api:501
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:188
static u32 gbp_rule_l3_redirect(const gbp_rule_t *gu, vlib_buffer_t *b0, int is_ip6)
gbp_scope_t gck_scope
Definition: gbp_contract.h:54
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
dpo_id_t gpd_dpo
Stacked DPO on DVR/ADJ of output interface.
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
static index_t gbp_policy_dpo_get_index(gbp_policy_dpo_t *gpd)
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:202
u32 index
Definition: flow_types.api:221
u8 * format_dpo_proto(u8 *s, va_list *args)
format a DPO protocol
Definition: dpo.c:178
Group Base Policy (GBP) defines:
Definition: gbp.h:42
dpo_proto_t gpd_proto
The protocol of packets using this DPO.
#define vnet_buffer(b)
Definition: buffer.h:417
enum gbp_policy_node_t_ gbp_policy_node_t
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
u16 dpoi_next_node
The next VLIB node to follow.
Definition: dpo.h:184
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
vlib_node_registration_t ip6_gbp_policy_dpo_node
(constructor) VLIB_REGISTER_NODE (ip6_gbp_policy_dpo_node)
vl_api_gbp_scope_t scope
Definition: gbp.api:78
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
void dpo_stack(dpo_type_t child_type, dpo_proto_t child_proto, dpo_id_t *dpo, const dpo_id_t *parent)
Stack one DPO object on another, and thus establish a child-parent relationship.
Definition: dpo.c:521