vxlan: multiarch optimization of vxlan
[vpp.git] / extras / deprecated / plugins / gbp / gbp_contract.h
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 #ifndef __GBP_CONTRACT_H__
17 #define __GBP_CONTRACT_H__
18
19 #include <plugins/gbp/gbp.h>
20 #include <plugins/gbp/gbp_types.h>
21
22 #define foreach_gbp_contract_error                         \
23   _(ALLOW_NO_SCLASS,    "allow-no-sclass")                 \
24   _(ALLOW_INTRA,        "allow-intra-sclass")              \
25   _(ALLOW_A_BIT,        "allow-a-bit-set")                 \
26   _(ALLOW_SCLASS_1,     "allow-sclass-1")                  \
27   _(ALLOW_CONTRACT,     "allow-contract")                  \
28   _(DROP_CONTRACT,      "drop-contract")                   \
29   _(DROP_ETHER_TYPE,    "drop-ether-type")                 \
30   _(DROP_NO_CONTRACT,   "drop-no-contract")                \
31   _(DROP_NO_DCLASS,     "drop-no-dclass")                  \
32   _(DROP_NO_RULE,       "drop-no-rule")
33
34 typedef enum
35 {
36 #define _(sym,str) GBP_CONTRACT_ERROR_##sym,
37   foreach_gbp_contract_error
38 #undef _
39     GBP_CONTRACT_N_ERROR,
40 #define GBP_CONTRACT_N_ERROR GBP_CONTRACT_N_ERROR
41 } gbp_contract_error_t;
42
43 extern char *gbp_contract_error_strings[GBP_CONTRACT_N_ERROR];
44
45 /**
46  * The key for an Contract
47  */
48 typedef struct gbp_contract_key_t_
49 {
50   union
51   {
52     struct
53     {
54       gbp_scope_t gck_scope;
55       /**
56        * source and destination EPGs for which the ACL applies
57        */
58       sclass_t gck_src;
59       sclass_t gck_dst;
60     };
61     u64 as_u64;
62   };
63 } gbp_contract_key_t;
64
65 typedef struct gbp_next_hop_t_
66 {
67   fib_node_t gnh_node;
68   ip46_address_t gnh_ip;
69   mac_address_t gnh_mac;
70   index_t gnh_gu;
71   index_t gnh_bd;
72   index_t gnh_rd;
73   u32 gnh_ge;
74   u32 gnh_sibling;
75   index_t gnh_ai[FIB_PROTOCOL_IP_MAX];
76 } gbp_next_hop_t;
77
78 #define foreach_gbp_hash_mode   \
79   _(SRC_IP, "src-ip")           \
80   _(DST_IP, "dst-ip")           \
81   _(SYMMETRIC, "symmetric")
82
83 typedef enum gbp_hash_mode_t_
84 {
85 #define _(v,s) GBP_HASH_MODE_##v,
86   foreach_gbp_hash_mode
87 #undef _
88 } gbp_hash_mode_t;
89
90 #define foreach_gbp_rule_action   \
91   _(PERMIT,   "permit")           \
92   _(DENY,     "deny")             \
93   _(REDIRECT, "redirect")
94
95 typedef enum gbp_rule_action_t_
96 {
97 #define _(v,s) GBP_RULE_##v,
98   foreach_gbp_rule_action
99 #undef _
100 } gbp_rule_action_t;
101
102 #define foreach_gbp_policy_node   \
103   _(L2, "L2")                     \
104   _(IP4, "ip4")                   \
105   _(IP6, "ip6")
106
107 typedef enum gbp_policy_node_t_
108 {
109 #define _(v,s) GBP_POLICY_NODE_##v,
110   foreach_gbp_policy_node
111 #undef _
112 } gbp_policy_node_t;
113 #define GBP_POLICY_N_NODES (GBP_POLICY_NODE_IP6+1)
114
115 #define FOR_EACH_GBP_POLICY_NODE(pnode)         \
116   for (pnode = GBP_POLICY_NODE_L2; pnode < GBP_POLICY_N_NODES; pnode++)
117
118 typedef struct gbp_rule_t_
119 {
120   gbp_rule_action_t gu_action;
121   gbp_hash_mode_t gu_hash_mode;
122   index_t *gu_nhs;
123
124   /**
125    * DPO of the load-balance object used to redirect
126    */
127   dpo_id_t gu_dpo[GBP_POLICY_N_NODES][FIB_PROTOCOL_IP_MAX];
128 } gbp_rule_t;
129
130 /**
131  * A Group Based Policy Contract.
132  *  Determines the ACL that applies to traffic pass between two endpoint groups
133  */
134 typedef struct gbp_contract_t_
135 {
136   /**
137    * source and destination EPGs
138    */
139   gbp_contract_key_t gc_key;
140
141   u32 gc_acl_index;
142   u32 gc_lc_index;
143
144   /**
145    * The ACL to apply for packets from the source to the destination EPG
146    */
147   index_t *gc_rules;
148
149   /**
150    * An ethertype whitelist
151    */
152   u16 *gc_allowed_ethertypes;
153 } gbp_contract_t;
154
155 /**
156  * EPG src,dst pair to ACL mapping table, aka contract DB
157  */
158 typedef struct gbp_contract_db_t_
159 {
160   /**
161    * We can form a u64 key from the pair, so use a simple hash table
162    */
163   uword *gc_hash;
164 } gbp_contract_db_t;
165
166 extern int gbp_contract_update (gbp_scope_t scope,
167                                 sclass_t sclass,
168                                 sclass_t dclass,
169                                 u32 acl_index,
170                                 index_t * rules,
171                                 u16 * allowed_ethertypes, u32 * stats_index);
172 extern int gbp_contract_delete (gbp_scope_t scope, sclass_t sclass,
173                                 sclass_t dclass);
174
175 extern index_t gbp_rule_alloc (gbp_rule_action_t action,
176                                gbp_hash_mode_t hash_mode, index_t * nhs);
177 extern void gbp_rule_free (index_t gui);
178 extern index_t gbp_next_hop_alloc (const ip46_address_t * ip,
179                                    index_t grd,
180                                    const mac_address_t * mac, index_t gbd);
181
182 typedef int (*gbp_contract_cb_t) (gbp_contract_t * gbpe, void *ctx);
183 extern void gbp_contract_walk (gbp_contract_cb_t bgpe, void *ctx);
184
185 extern u8 *format_gbp_rule_action (u8 * s, va_list * args);
186 extern u8 *format_gbp_contract (u8 * s, va_list * args);
187
188 /**
189  * DP functions and databases
190  */
191 extern gbp_contract_db_t gbp_contract_db;
192
193 always_inline index_t
194 gbp_contract_find (gbp_contract_key_t * key)
195 {
196   uword *p;
197
198   p = hash_get (gbp_contract_db.gc_hash, key->as_u64);
199
200   if (NULL != p)
201     return (p[0]);
202
203   return (INDEX_INVALID);
204 }
205
206 extern gbp_contract_t *gbp_contract_pool;
207
208 always_inline gbp_contract_t *
209 gbp_contract_get (index_t gci)
210 {
211   return (pool_elt_at_index (gbp_contract_pool, gci));
212 }
213
214 extern gbp_rule_t *gbp_rule_pool;
215
216 always_inline gbp_rule_t *
217 gbp_rule_get (index_t gui)
218 {
219   return (pool_elt_at_index (gbp_rule_pool, gui));
220 }
221
222 extern vlib_combined_counter_main_t gbp_contract_permit_counters;
223 extern vlib_combined_counter_main_t gbp_contract_drop_counters;
224
225 typedef enum
226 {
227   GBP_CONTRACT_APPLY_L2,
228   GBP_CONTRACT_APPLY_IP4,
229   GBP_CONTRACT_APPLY_IP6,
230 } gbp_contract_apply_type_t;
231
232 static_always_inline gbp_rule_action_t
233 gbp_contract_apply (vlib_main_t * vm, gbp_main_t * gm,
234                     gbp_contract_key_t * key, vlib_buffer_t * b,
235                     gbp_rule_t ** rule, u32 * intra, u32 * sclass1,
236                     u32 * acl_match, u32 * rule_match,
237                     gbp_contract_error_t * err,
238                     gbp_contract_apply_type_t type)
239 {
240   fa_5tuple_opaque_t fa_5tuple;
241   const gbp_contract_t *contract;
242   index_t contract_index;
243   u32 acl_pos, trace_bitmap;
244   u16 etype;
245   u8 ip6, action;
246
247   *rule = 0;
248   trace_bitmap = 0;
249
250   if (key->gck_src == key->gck_dst)
251     {
252       /* intra-epg allowed */
253       (*intra)++;
254       *err = GBP_CONTRACT_ERROR_ALLOW_INTRA;
255       return GBP_RULE_PERMIT;
256     }
257
258   if (1 == key->gck_src || 1 == key->gck_dst)
259     {
260       /* sclass 1 allowed */
261       (*sclass1)++;
262       *err = GBP_CONTRACT_ERROR_ALLOW_SCLASS_1;
263       return GBP_RULE_PERMIT;
264     }
265
266   /* look for contract */
267   contract_index = gbp_contract_find (key);
268   if (INDEX_INVALID == contract_index)
269     {
270       *err = GBP_CONTRACT_ERROR_DROP_NO_CONTRACT;
271       return GBP_RULE_DENY;
272     }
273
274   contract = gbp_contract_get (contract_index);
275
276   *err = GBP_CONTRACT_ERROR_DROP_CONTRACT;
277
278   switch (type)
279     {
280     case GBP_CONTRACT_APPLY_IP4:
281       ip6 = 0;
282       break;
283     case GBP_CONTRACT_APPLY_IP6:
284       ip6 = 1;
285       break;
286     case GBP_CONTRACT_APPLY_L2:
287       {
288         /* check ethertype */
289         etype =
290           ((u16 *) (vlib_buffer_get_current (b) +
291                     vnet_buffer (b)->l2.l2_len))[-1];
292
293         if (~0 == vec_search (contract->gc_allowed_ethertypes, etype))
294           {
295             *err = GBP_CONTRACT_ERROR_DROP_ETHER_TYPE;
296             goto contract_deny;
297           }
298
299         switch (clib_net_to_host_u16 (etype))
300           {
301           case ETHERNET_TYPE_IP4:
302             ip6 = 0;
303             break;
304           case ETHERNET_TYPE_IP6:
305             ip6 = 1;
306             break;
307           default:
308             goto contract_deny;
309           }
310       }
311       break;
312     }
313
314   /* check ACL */
315   action = 0;
316   acl_plugin_fill_5tuple_inline (gm->acl_plugin.p_acl_main,
317                                  contract->gc_lc_index, b, ip6,
318                                  GBP_CONTRACT_APPLY_L2 != type /* input */ ,
319                                  GBP_CONTRACT_APPLY_L2 == type /* l2_path */ ,
320                                  &fa_5tuple);
321   acl_plugin_match_5tuple_inline (gm->acl_plugin.p_acl_main,
322                                   contract->gc_lc_index, &fa_5tuple, ip6,
323                                   &action, &acl_pos, acl_match, rule_match,
324                                   &trace_bitmap);
325   if (action <= 0)
326     goto contract_deny;
327
328   if (PREDICT_FALSE (*rule_match >= vec_len (contract->gc_rules)))
329     {
330       *err = GBP_CONTRACT_ERROR_DROP_NO_RULE;
331       goto contract_deny;
332     }
333
334   *rule = gbp_rule_get (contract->gc_rules[*rule_match]);
335   switch ((*rule)->gu_action)
336     {
337     case GBP_RULE_PERMIT:
338     case GBP_RULE_REDIRECT:
339       *err = GBP_CONTRACT_ERROR_ALLOW_CONTRACT;
340       vlib_increment_combined_counter (&gbp_contract_permit_counters,
341                                        vm->thread_index, contract_index, 1,
342                                        vlib_buffer_length_in_chain (vm, b));
343       return (*rule)->gu_action;
344     case GBP_RULE_DENY:
345       break;
346     }
347
348 contract_deny:
349   vlib_increment_combined_counter (&gbp_contract_drop_counters,
350                                    vm->thread_index, contract_index, 1,
351                                    vlib_buffer_length_in_chain (vm, b));
352   return GBP_RULE_DENY;
353 }
354
355 #endif /* __GBP_CONTRACT_H__ */
356 /*
357  * fd.io coding-style-patch-verification: ON
358  *
359  * Local Variables:
360  * eval: (c-set-style "gnu")
361  * End:
362  */