gbp: Add support for ACL
[vpp.git] / src / plugins / gbp / gbp_contract.c
1 /*
2  * gbp.h : Group Based Policy
3  *
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:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #include <plugins/gbp/gbp.h>
19
20 /**
21  * Single contract DB instance
22  */
23 gbp_contract_db_t gbp_contract_db;
24
25 void
26 gbp_contract_update (epg_id_t src_epg, epg_id_t dst_epg, u32 acl_index)
27 {
28   gbp_main_t *gm = &gbp_main;
29   u32 *acl_vec = 0;
30   gbp_contract_value_t value = {
31     .gc_lc_index = ~0,
32     .gc_acl_index = ~0,
33   };
34   uword *p;
35
36   gbp_contract_key_t key = {
37     .gck_src = src_epg,
38     .gck_dst = dst_epg,
39   };
40
41   if (~0 == gm->gbp_acl_user_id)
42     {
43       acl_plugin_exports_init (&gm->acl_plugin);
44       gm->gbp_acl_user_id =
45         gm->acl_plugin.register_user_module ("GBP ACL", "src-epg", "dst-epg");
46     }
47
48   p = hash_get (gbp_contract_db.gc_hash, key.as_u64);
49   if (p != NULL)
50     {
51       value.as_u64 = p[0];
52     }
53   else
54     {
55       value.gc_lc_index =
56         gm->acl_plugin.get_lookup_context_index (gm->gbp_acl_user_id, src_epg,
57                                                  dst_epg);
58       value.gc_acl_index = acl_index;
59       hash_set (gbp_contract_db.gc_hash, key.as_u64, value.as_u64);
60     }
61
62   if (value.gc_lc_index == ~0)
63     return;
64   vec_add1 (acl_vec, acl_index);
65   gm->acl_plugin.set_acl_vec_for_context (value.gc_lc_index, acl_vec);
66   vec_free (acl_vec);
67 }
68
69 void
70 gbp_contract_delete (epg_id_t src_epg, epg_id_t dst_epg)
71 {
72   gbp_main_t *gm = &gbp_main;
73   uword *p;
74   gbp_contract_value_t value;
75   gbp_contract_key_t key = {
76     .gck_src = src_epg,
77     .gck_dst = dst_epg,
78   };
79
80   p = hash_get (gbp_contract_db.gc_hash, key.as_u64);
81   if (p != NULL)
82     {
83       value.as_u64 = p[0];
84       gm->acl_plugin.put_lookup_context_index (value.gc_lc_index);
85     }
86   hash_unset (gbp_contract_db.gc_hash, key.as_u64);
87 }
88
89 void
90 gbp_contract_walk (gbp_contract_cb_t cb, void *ctx)
91 {
92   gbp_contract_key_t key;
93   gbp_contract_value_t value;
94
95   /* *INDENT-OFF* */
96   hash_foreach(key.as_u64, value.as_u64, gbp_contract_db.gc_hash,
97   ({
98     gbp_contract_t gbpc = {
99       .gc_key = key,
100       .gc_value = value,
101     };
102
103     if (!cb(&gbpc, ctx))
104       break;
105   }));
106   /* *INDENT-ON* */
107 }
108
109 static clib_error_t *
110 gbp_contract_cli (vlib_main_t * vm,
111                   unformat_input_t * input, vlib_cli_command_t * cmd)
112 {
113   epg_id_t src_epg_id = EPG_INVALID, dst_epg_id = EPG_INVALID;
114   u32 acl_index = ~0;
115   u8 add = 1;
116
117   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
118     {
119       if (unformat (input, "add"))
120         add = 1;
121       else if (unformat (input, "del"))
122         add = 0;
123       else if (unformat (input, "src-epg %d", &src_epg_id))
124         ;
125       else if (unformat (input, "dst-epg %d", &dst_epg_id))
126         ;
127       else if (unformat (input, "acl-index %d", &acl_index))
128         ;
129       else
130         break;
131     }
132
133   if (EPG_INVALID == src_epg_id)
134     return clib_error_return (0, "Source EPG-ID must be specified");
135   if (EPG_INVALID == dst_epg_id)
136     return clib_error_return (0, "Destination EPG-ID must be specified");
137
138   if (add)
139     {
140       gbp_contract_update (src_epg_id, dst_epg_id, acl_index);
141     }
142   else
143     {
144       gbp_contract_delete (src_epg_id, dst_epg_id);
145     }
146
147   return (NULL);
148 }
149
150 /*?
151  * Configure a GBP Contract
152  *
153  * @cliexpar
154  * @cliexstart{set gbp contract [del] src-epg <ID> dst-epg <ID> acl-index <ACL>}
155  * @cliexend
156  ?*/
157 /* *INDENT-OFF* */
158 VLIB_CLI_COMMAND (gbp_contract_cli_node, static) =
159 {
160   .path = "gbp contract",
161   .short_help =
162     "gbp contract [del] src-epg <ID> dst-epg <ID> acl-index <ACL>",
163   .function = gbp_contract_cli,
164 };
165 /* *INDENT-ON* */
166
167 static clib_error_t *
168 gbp_contract_show (vlib_main_t * vm,
169                    unformat_input_t * input, vlib_cli_command_t * cmd)
170 {
171   gbp_contract_key_t key;
172   gbp_contract_value_t value;
173
174   vlib_cli_output (vm, "Contracts:");
175
176   /* *INDENT-OFF* */
177   hash_foreach (key.as_u64, value.as_u64, gbp_contract_db.gc_hash,
178   {
179     vlib_cli_output (vm, "  {%d,%d} -> %d", key.gck_src,
180                      key.gck_dst, value.gc_acl_index);
181   });
182   /* *INDENT-ON* */
183
184   return (NULL);
185 }
186
187 /*?
188  * Show Group Based Policy Contracts
189  *
190  * @cliexpar
191  * @cliexstart{show gbp contract}
192  * @cliexend
193  ?*/
194 /* *INDENT-OFF* */
195 VLIB_CLI_COMMAND (gbp_contract_show_node, static) = {
196   .path = "show gbp contract",
197   .short_help = "show gbp contract\n",
198   .function = gbp_contract_show,
199 };
200 /* *INDENT-ON* */
201
202 /*
203  * fd.io coding-style-patch-verification: ON
204  *
205  * Local Variables:
206  * eval: (c-set-style "gnu")
207  * End:
208  */