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