lisp: Move to plugin
[vpp.git] / src / plugins / lisp / lisp-gpe / lisp_gpe_tenant.c
1 /*
2  * Copyright (c) 2016 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 <lisp/lisp-gpe/lisp_gpe_tenant.h>
17
18 /**
19  * The pool of all tenants
20  */
21 static lisp_gpe_tenant_t *lisp_gpe_tenant_pool;
22
23 /**
24  * The hash table of all tenants: key:{VNI}.
25  */
26 uword *lisp_gpe_tenant_db;
27
28 static lisp_gpe_tenant_t *
29 lisp_gpe_tenant_find (u32 vni)
30 {
31   uword *p;
32
33   p = hash_get (lisp_gpe_tenant_db, vni);
34
35   if (NULL == p)
36     return (NULL);
37
38   return (pool_elt_at_index (lisp_gpe_tenant_pool, p[0]));
39 }
40
41 static lisp_gpe_tenant_t *
42 lisp_gpe_tenant_find_or_create_i (u32 vni)
43 {
44   lisp_gpe_tenant_t *lt;
45
46   lt = lisp_gpe_tenant_find (vni);
47
48   if (NULL == lt)
49     {
50       pool_get (lisp_gpe_tenant_pool, lt);
51       clib_memset (lt, 0, sizeof (*lt));
52
53       lt->lt_vni = vni;
54       lt->lt_table_id = ~0;
55       lt->lt_bd_id = ~0;
56
57       hash_set (lisp_gpe_tenant_db, vni, lt - lisp_gpe_tenant_pool);
58     }
59
60   return (lt);
61 }
62
63 /**
64  * @brief Find or create a tenant for the given VNI
65  */
66 u32
67 lisp_gpe_tenant_find_or_create (u32 vni)
68 {
69   lisp_gpe_tenant_t *lt;
70
71   lt = lisp_gpe_tenant_find (vni);
72
73   if (NULL == lt)
74     {
75       lt = lisp_gpe_tenant_find_or_create_i (vni);
76     }
77
78   return (lt - lisp_gpe_tenant_pool);
79 }
80
81 /**
82  * @brief If there are no more locks/users of te tenant, then delete it
83  */
84 static void
85 lisp_gpe_tenant_delete_if_empty (lisp_gpe_tenant_t * lt)
86 {
87   int i;
88
89   for (i = 0; i < LISP_GPE_TENANT_LOCK_NUM; i++)
90     {
91       if (lt->lt_locks[i])
92         return;
93     }
94
95   hash_unset (lisp_gpe_tenant_db, lt->lt_vni);
96   pool_put (lisp_gpe_tenant_pool, lt);
97 }
98
99 /**
100  * @brief Add/create and lock a new or find and lock the existing L3
101  * interface for the tenant
102  *
103  * @paran vni The tenant's VNI
104  * @param table_id the Tenant's L3 table ID.
105  * @param with_default_route Install default route for the interface
106  *
107  * @return the SW IF index of the L3 interface
108  */
109 u32
110 lisp_gpe_tenant_l3_iface_add_or_lock (u32 vni, u32 table_id,
111                                       u8 with_default_route)
112 {
113   lisp_gpe_tenant_t *lt;
114
115   lt = lisp_gpe_tenant_find_or_create_i (vni);
116
117   if (~0 == lt->lt_table_id)
118     lt->lt_table_id = table_id;
119
120   ASSERT (lt->lt_table_id == table_id);
121
122   if (0 == lt->lt_locks[LISP_GPE_TENANT_LOCK_L3_IFACE])
123     {
124       /* create the l3 interface since there are currently no users of it */
125       lt->lt_l3_sw_if_index =
126         lisp_gpe_add_l3_iface (&lisp_gpe_main, vni, table_id,
127                                with_default_route);
128     }
129
130   lt->lt_locks[LISP_GPE_TENANT_LOCK_L3_IFACE]++;
131
132   return (lt->lt_l3_sw_if_index);
133 }
134
135 /**
136  * @brief Release the lock held on the tenant's L3 interface
137  */
138 void
139 lisp_gpe_tenant_l3_iface_unlock (u32 vni)
140 {
141   lisp_gpe_tenant_t *lt;
142
143   lt = lisp_gpe_tenant_find (vni);
144
145   if (NULL == lt)
146     {
147       clib_warning ("No tenant for VNI %d", vni);
148       return;
149     }
150
151   if (0 == lt->lt_locks[LISP_GPE_TENANT_LOCK_L3_IFACE])
152     {
153       clib_warning ("No L3 interface for tenant VNI %d", vni);
154       return;
155     }
156
157   lt->lt_locks[LISP_GPE_TENANT_LOCK_L3_IFACE]--;
158
159   if (0 == lt->lt_locks[LISP_GPE_TENANT_LOCK_L3_IFACE])
160     {
161       /* the last user has gone, so delete the l3 interface */
162       lisp_gpe_del_l3_iface (&lisp_gpe_main, vni, lt->lt_table_id);
163     }
164
165   /*
166    * If there are no more locks on any tenant managed resource, then
167    * this tenant is toast.
168    */
169   lisp_gpe_tenant_delete_if_empty (lt);
170 }
171
172 /**
173  * @brief Add/create and lock a new or find and lock the existing L2
174  * interface for the tenant
175  *
176  * @paran vni The tenant's VNI
177  * @param table_id the Tenant's L2 Bridge Domain ID.
178  *
179  * @return the SW IF index of the L2 interface
180  */
181 u32
182 lisp_gpe_tenant_l2_iface_add_or_lock (u32 vni, u32 bd_id)
183 {
184   lisp_gpe_tenant_t *lt;
185
186   lt = lisp_gpe_tenant_find_or_create_i (vni);
187
188   if (NULL == lt)
189     {
190       clib_warning ("No tenant for VNI %d", vni);
191       return ~0;
192     }
193
194   if (~0 == lt->lt_bd_id)
195     lt->lt_bd_id = bd_id;
196
197   ASSERT (lt->lt_bd_id == bd_id);
198
199   if (0 == lt->lt_locks[LISP_GPE_TENANT_LOCK_L2_IFACE])
200     {
201       /* create the l2 interface since there are currently no users of it */
202       lt->lt_l2_sw_if_index =
203         lisp_gpe_add_l2_iface (&lisp_gpe_main, vni, bd_id);
204     }
205
206   lt->lt_locks[LISP_GPE_TENANT_LOCK_L2_IFACE]++;
207
208   return (lt->lt_l2_sw_if_index);
209 }
210
211 /**
212  * @brief Release the lock held on the tenant's L3 interface
213  */
214 void
215 lisp_gpe_tenant_l2_iface_unlock (u32 vni)
216 {
217   lisp_gpe_tenant_t *lt;
218
219   lt = lisp_gpe_tenant_find (vni);
220
221   if (NULL == lt)
222     {
223       clib_warning ("No tenant for VNI %d", vni);
224       return;
225     }
226
227   if (0 == lt->lt_locks[LISP_GPE_TENANT_LOCK_L2_IFACE])
228     {
229       clib_warning ("No L2 interface for tenant VNI %d", vni);
230       return;
231     }
232
233   lt->lt_locks[LISP_GPE_TENANT_LOCK_L2_IFACE]--;
234
235   if (0 == lt->lt_locks[LISP_GPE_TENANT_LOCK_L2_IFACE])
236     {
237       /* the last user has gone, so delete the l2 interface */
238       lisp_gpe_del_l2_iface (&lisp_gpe_main, vni, lt->lt_bd_id);
239     }
240
241   /*
242    * If there are no more locks on any tenant managed resource, then
243    * this tenant is toast.
244    */
245   lisp_gpe_tenant_delete_if_empty (lt);
246 }
247
248 /**
249  * @brief get a const pointer to the tenant object
250  */
251 const lisp_gpe_tenant_t *
252 lisp_gpe_tenant_get (u32 index)
253 {
254   return (pool_elt_at_index (lisp_gpe_tenant_pool, index));
255 }
256
257 /**
258  * @brief Flush/delete ALL the tenants
259  */
260 void
261 lisp_gpe_tenant_flush (void)
262 {
263   lisp_gpe_tenant_t *lt;
264
265   /* *INDENT-OFF* */
266   pool_foreach(lt, lisp_gpe_tenant_pool,
267   ({
268     lisp_gpe_tenant_l2_iface_unlock(lt->lt_vni);
269     lisp_gpe_tenant_l3_iface_unlock(lt->lt_vni);
270   }));
271   /* *INDENT-ON* */
272 }
273
274 /**
275  * @brief Show/display one tenant
276  */
277 static u8 *
278 format_lisp_gpe_tenant (u8 * s, va_list * ap)
279 {
280   const lisp_gpe_tenant_t *lt = va_arg (*ap, lisp_gpe_tenant_t *);
281
282   s = format (s, "VNI:%d ", lt->lt_vni);
283
284   if (lt->lt_table_id != ~0)
285     {
286       s = format (s, "VRF:%d ", lt->lt_table_id);
287       s = format (s, "L3-SW-IF:%d ", lt->lt_l3_sw_if_index);
288     }
289
290   if (lt->lt_bd_id != ~0)
291     {
292       s = format (s, "BD-ID:%d ", lt->lt_bd_id);
293       s = format (s, "L2-SW-IF:%d ", lt->lt_l2_sw_if_index);
294     }
295
296   return (s);
297 }
298
299 /**
300  * @brief CLI command to show LISP-GPE tenant.
301  */
302 static clib_error_t *
303 lisp_gpe_tenant_show (vlib_main_t * vm,
304                       unformat_input_t * input, vlib_cli_command_t * cmd)
305 {
306   lisp_gpe_tenant_t *lt;
307
308   /* *INDENT-OFF* */
309   pool_foreach (lt, lisp_gpe_tenant_pool,
310   ({
311     vlib_cli_output (vm, "%U", format_lisp_gpe_tenant, lt);
312   }));
313   /* *INDENT-ON* */
314
315   return 0;
316 }
317
318 /* *INDENT-OFF* */
319 VLIB_CLI_COMMAND (lisp_gpe_tenant_command) = {
320   .path = "show gpe tenant",
321   .short_help = "show gpe tenant",
322   .function = lisp_gpe_tenant_show,
323 };
324 /* *INDENT-ON* */
325
326
327 /*
328  * fd.io coding-style-patch-verification: ON
329  *
330  * Local Variables:
331  * eval: (c-set-style "gnu")
332  * End:
333  */