GBP V2
[vpp.git] / src / plugins / gbp / gbp_endpoint_group.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_endpoint_group.h>
19 #include <plugins/gbp/gbp_endpoint.h>
20
21 #include <vnet/dpo/dvr_dpo.h>
22 #include <vnet/fib/fib_table.h>
23
24 /**
25  * Pool of GBP endpoint_groups
26  */
27 gbp_endpoint_group_t *gbp_endpoint_group_pool;
28
29 /**
30  * DB of endpoint_groups
31  */
32 gbp_endpoint_group_db_t gbp_endpoint_group_db;
33
34 gbp_endpoint_group_t *
35 gbp_endpoint_group_find (epg_id_t epg_id)
36 {
37   uword *p;
38
39   p = hash_get (gbp_endpoint_group_db.gepg_hash, epg_id);
40
41   if (NULL != p)
42     return (pool_elt_at_index (gbp_endpoint_group_pool, p[0]));
43
44   return (NULL);
45 }
46
47 int
48 gbp_endpoint_group_add (epg_id_t epg_id,
49                         u32 bd_id,
50                         u32 ip4_table_id,
51                         u32 ip6_table_id, u32 uplink_sw_if_index)
52 {
53   gbp_endpoint_group_t *gepg;
54
55   gepg = gbp_endpoint_group_find (epg_id);
56
57   if (NULL == gepg)
58     {
59       fib_protocol_t fproto;
60
61       pool_get (gbp_endpoint_group_pool, gepg);
62       memset (gepg, 0, sizeof (*gepg));
63
64       gepg->gepg_id = epg_id;
65       gepg->gepg_bd = bd_id;
66       gepg->gepg_rd[FIB_PROTOCOL_IP4] = ip4_table_id;
67       gepg->gepg_rd[FIB_PROTOCOL_IP6] = ip6_table_id;
68       gepg->gepg_uplink_sw_if_index = uplink_sw_if_index;
69
70       /*
71        * an egress DVR dpo for internal subnets to use when sending
72        * on the uplink interface
73        */
74       FOR_EACH_FIB_IP_PROTOCOL (fproto)
75       {
76         gepg->gepg_fib_index[fproto] =
77           fib_table_find_or_create_and_lock (fproto,
78                                              gepg->gepg_rd[fproto],
79                                              FIB_SOURCE_PLUGIN_HI);
80
81         if (~0 == gepg->gepg_fib_index[fproto])
82           {
83             return (VNET_API_ERROR_NO_SUCH_FIB);
84           }
85
86         dvr_dpo_add_or_lock (uplink_sw_if_index,
87                              fib_proto_to_dpo (fproto),
88                              &gepg->gepg_dpo[fproto]);
89       }
90
91       /*
92        * packets direct from the uplink have had policy applied
93        */
94       l2input_intf_bitmap_enable (gepg->gepg_uplink_sw_if_index,
95                                   L2INPUT_FEAT_GBP_NULL_CLASSIFY, 1);
96
97       hash_set (gbp_endpoint_group_db.gepg_hash,
98                 gepg->gepg_id, gepg - gbp_endpoint_group_pool);
99
100     }
101
102   return (0);
103 }
104
105 void
106 gbp_endpoint_group_delete (epg_id_t epg_id)
107 {
108   gbp_endpoint_group_t *gepg;
109   uword *p;
110
111   p = hash_get (gbp_endpoint_group_db.gepg_hash, epg_id);
112
113   if (NULL != p)
114     {
115       fib_protocol_t fproto;
116
117       gepg = pool_elt_at_index (gbp_endpoint_group_pool, p[0]);
118
119       l2input_intf_bitmap_enable (gepg->gepg_uplink_sw_if_index,
120                                   L2INPUT_FEAT_GBP_NULL_CLASSIFY, 0);
121
122       FOR_EACH_FIB_IP_PROTOCOL (fproto)
123       {
124         dpo_reset (&gepg->gepg_dpo[fproto]);
125         fib_table_unlock (gepg->gepg_fib_index[fproto],
126                           fproto, FIB_SOURCE_PLUGIN_HI);
127       }
128
129       hash_unset (gbp_endpoint_group_db.gepg_hash, epg_id);
130
131       pool_put (gbp_endpoint_group_pool, gepg);
132     }
133 }
134
135 void
136 gbp_endpoint_group_walk (gbp_endpoint_group_cb_t cb, void *ctx)
137 {
138   gbp_endpoint_group_t *gbpe;
139
140   /* *INDENT-OFF* */
141   pool_foreach(gbpe, gbp_endpoint_group_pool,
142   {
143     if (!cb(gbpe, ctx))
144       break;
145   });
146   /* *INDENT-ON* */
147 }
148
149 static clib_error_t *
150 gbp_endpoint_group_cli (vlib_main_t * vm,
151                         unformat_input_t * input, vlib_cli_command_t * cmd)
152 {
153   vnet_main_t *vnm = vnet_get_main ();
154   epg_id_t epg_id = EPG_INVALID;
155   u32 uplink_sw_if_index = ~0;
156   u32 bd_id = ~0;
157   u32 rd_id = ~0;
158   u8 add = 1;
159
160   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
161     {
162       if (unformat (input, "%U", unformat_vnet_sw_interface,
163                     vnm, &uplink_sw_if_index))
164         ;
165       else if (unformat (input, "add"))
166         add = 1;
167       else if (unformat (input, "del"))
168         add = 0;
169       else if (unformat (input, "epg %d", &epg_id))
170         ;
171       else if (unformat (input, "bd %d", &bd_id))
172         ;
173       else if (unformat (input, "rd %d", &rd_id))
174         ;
175       else
176         break;
177     }
178
179   if (EPG_INVALID == epg_id)
180     return clib_error_return (0, "EPG-ID must be specified");
181
182   if (add)
183     {
184       if (~0 == uplink_sw_if_index)
185         return clib_error_return (0, "interface must be specified");
186       if (~0 == bd_id)
187         return clib_error_return (0, "Bridge-domain must be specified");
188       if (~0 == rd_id)
189         return clib_error_return (0, "route-domain must be specified");
190
191       gbp_endpoint_group_add (epg_id, bd_id, rd_id, rd_id,
192                               uplink_sw_if_index);
193     }
194   else
195     gbp_endpoint_group_delete (epg_id);
196
197   return (NULL);
198 }
199
200 /*?
201  * Configure a GBP Endpoint Group
202  *
203  * @cliexpar
204  * @cliexstart{set gbp endpoint-group [del] epg <ID> bd <ID> <interface>}
205  * @cliexend
206  ?*/
207 /* *INDENT-OFF* */
208 VLIB_CLI_COMMAND (gbp_endpoint_group_cli_node, static) = {
209   .path = "gbp endpoint-group",
210   .short_help = "gbp endpoint-group [del] epg <ID> bd <ID> <interface>",
211   .function = gbp_endpoint_group_cli,
212 };
213
214 static int
215 gbp_endpoint_group_show_one (gbp_endpoint_group_t *gepg, void *ctx)
216 {
217   vnet_main_t *vnm = vnet_get_main ();
218   vlib_main_t *vm;
219
220   vm = ctx;
221   vlib_cli_output (vm, "  %d, bd:%d, ip4:%d ip6:%d uplink:%U",
222                    gepg->gepg_id,
223                    gepg->gepg_bd,
224                    gepg->gepg_rd[FIB_PROTOCOL_IP4],
225                    gepg->gepg_rd[FIB_PROTOCOL_IP6],
226                    format_vnet_sw_if_index_name, vnm, gepg->gepg_uplink_sw_if_index);
227
228   return (1);
229 }
230
231 static clib_error_t *
232 gbp_endpoint_group_show (vlib_main_t * vm,
233                    unformat_input_t * input, vlib_cli_command_t * cmd)
234 {
235   vlib_cli_output (vm, "Endpoint-Groups:");
236   gbp_endpoint_group_walk (gbp_endpoint_group_show_one, vm);
237
238   return (NULL);
239 }
240
241
242 /*?
243  * Show Group Based Policy Endpoint_Groups and derived information
244  *
245  * @cliexpar
246  * @cliexstart{show gbp endpoint_group}
247  * @cliexend
248  ?*/
249 /* *INDENT-OFF* */
250 VLIB_CLI_COMMAND (gbp_endpoint_group_show_node, static) = {
251   .path = "show gbp endpoint-group",
252   .short_help = "show gbp endpoint-group\n",
253   .function = gbp_endpoint_group_show,
254 };
255 /* *INDENT-ON* */
256
257 /*
258  * fd.io coding-style-patch-verification: ON
259  *
260  * Local Variables:
261  * eval: (c-set-style "gnu")
262  * End:
263  */