vxlan: multiarch optimization of vxlan
[vpp.git] / extras / deprecated / plugins / gbp / gbp_itf.c
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 #include <plugins/gbp/gbp_itf.h>
17 #include <plugins/gbp/gbp_bridge_domain.h>
18 #include <plugins/gbp/gbp_route_domain.h>
19
20 #include <vnet/ip/ip.h>
21
22 #define foreach_gbp_itf_mode  \
23   _(L2, "l2")                 \
24   _(L3, "L3")
25
26 typedef enum gbp_ift_mode_t_
27 {
28 #define _(s,v)  GBP_ITF_MODE_##s,
29   foreach_gbp_itf_mode
30 #undef _
31 } gbp_itf_mode_t;
32
33 /**
34  * Attributes and configurations attached to interfaces by GBP
35  */
36 typedef struct gbp_itf_t_
37 {
38   /**
39    * Number of references to this interface
40    */
41   u32 gi_locks;
42
43   /**
44    * The interface this wrapper is managing
45    */
46   u32 gi_sw_if_index;
47
48   /**
49    * The mode of the interface
50    */
51   gbp_itf_mode_t gi_mode;
52
53   /**
54    * Users of this interface - this is encoded in the user's handle
55    */
56   u32 *gi_users;
57
58   /**
59    * L2/L3 Features configured by each user
60    */
61   u32 *gi_input_fbs;
62   u32 gi_input_fb;
63   u32 *gi_output_fbs;
64   u32 gi_output_fb;
65
66   /**
67    * function to call when the interface is deleted.
68    */
69   gbp_itf_free_fn_t gi_free_fn;
70
71   union
72   {
73     /**
74      * GBP BD or RD index
75      */
76     u32 gi_gbi;
77     index_t gi_gri;
78   };
79 } gbp_itf_t;
80
81 static gbp_itf_t *gbp_itf_pool;
82 static uword *gbp_itf_db;
83
84 static const char *gbp_itf_feat_bit_pos_to_arc[] = {
85 #define _(s,v,a) [GBP_ITF_L3_FEAT_POS_##s] = a,
86   foreach_gdb_l3_feature
87 #undef _
88 };
89
90 static const char *gbp_itf_feat_bit_pos_to_feat[] = {
91 #define _(s,v,a) [GBP_ITF_L3_FEAT_POS_##s] = v,
92   foreach_gdb_l3_feature
93 #undef _
94 };
95
96 u8 *
97 format_gbp_itf_l3_feat (u8 * s, va_list * args)
98 {
99   gbp_itf_l3_feat_t flags = va_arg (*args, gbp_itf_l3_feat_t);
100
101 #define _(a, b, c)                              \
102   if (flags & GBP_ITF_L3_FEAT_##a)              \
103     s = format (s, "%s ", b);
104   foreach_gdb_l3_feature
105 #undef _
106     return (s);
107 }
108
109 void
110 gbp_itf_hdl_reset (gbp_itf_hdl_t * gh)
111 {
112   *gh = GBP_ITF_HDL_INVALID;
113 }
114
115 bool
116 gbp_itf_hdl_is_valid (gbp_itf_hdl_t gh)
117 {
118   return (gh.gh_which != GBP_ITF_HDL_INVALID.gh_which);
119 }
120
121 static gbp_itf_t *
122 gbp_itf_get (index_t gii)
123 {
124   if (pool_is_free_index (gbp_itf_pool, gii))
125     return (NULL);
126
127   return (pool_elt_at_index (gbp_itf_pool, gii));
128 }
129
130 static gbp_itf_t *
131 gbp_itf_find (u32 sw_if_index)
132 {
133   uword *p;
134
135   p = hash_get (gbp_itf_db, sw_if_index);
136
137   if (NULL != p)
138     return (gbp_itf_get (p[0]));
139
140   return (NULL);
141 }
142
143 static gbp_itf_t *
144 gbp_itf_find_hdl (gbp_itf_hdl_t gh)
145 {
146   return (gbp_itf_find (gh.gh_which));
147 }
148
149 u32
150 gbp_itf_get_sw_if_index (gbp_itf_hdl_t hdl)
151 {
152   return (hdl.gh_which);
153 }
154
155 static gbp_itf_hdl_t
156 gbp_itf_mk_hdl (gbp_itf_t * gi)
157 {
158   gbp_itf_hdl_t gh;
159   u32 *useri;
160
161   pool_get (gi->gi_users, useri);
162   *useri = 0;
163
164   gh.gh_who = useri - gi->gi_users;
165   gh.gh_which = gi->gi_sw_if_index;
166
167   return (gh);
168 }
169
170 static gbp_itf_hdl_t
171 gbp_itf_l2_add_and_lock_i (u32 sw_if_index, index_t gbi, gbp_itf_free_fn_t ff)
172 {
173   gbp_itf_t *gi;
174
175   gi = gbp_itf_find (sw_if_index);
176
177   if (NULL == gi)
178     {
179       pool_get_zero (gbp_itf_pool, gi);
180
181       gi->gi_sw_if_index = sw_if_index;
182       gi->gi_gbi = gbi;
183       gi->gi_mode = GBP_ITF_MODE_L2;
184       gi->gi_free_fn = ff;
185
186       gbp_bridge_domain_itf_add (gi->gi_gbi, gi->gi_sw_if_index,
187                                  L2_BD_PORT_TYPE_NORMAL);
188
189       hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool);
190     }
191
192   gi->gi_locks++;
193
194   return (gbp_itf_mk_hdl (gi));
195 }
196
197 gbp_itf_hdl_t
198 gbp_itf_l2_add_and_lock (u32 sw_if_index, index_t gbi)
199 {
200   return (gbp_itf_l2_add_and_lock_i (sw_if_index, gbi, NULL));
201 }
202
203 gbp_itf_hdl_t
204 gbp_itf_l2_add_and_lock_w_free (u32 sw_if_index,
205                                 index_t gbi, gbp_itf_free_fn_t ff)
206 {
207   return (gbp_itf_l2_add_and_lock_i (sw_if_index, gbi, ff));
208 }
209
210 gbp_itf_hdl_t
211 gbp_itf_l3_add_and_lock_i (u32 sw_if_index, index_t gri, gbp_itf_free_fn_t ff)
212 {
213   gbp_itf_t *gi;
214
215   gi = gbp_itf_find (sw_if_index);
216
217   if (NULL == gi)
218     {
219       const gbp_route_domain_t *grd;
220       fib_protocol_t fproto;
221
222       pool_get_zero (gbp_itf_pool, gi);
223
224       gi->gi_sw_if_index = sw_if_index;
225       gi->gi_mode = GBP_ITF_MODE_L3;
226       gi->gi_gri = gri;
227       gi->gi_free_fn = ff;
228
229       grd = gbp_route_domain_get (gi->gi_gri);
230
231       ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 1);
232       ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 1);
233
234       FOR_EACH_FIB_IP_PROTOCOL (fproto)
235       ip_table_bind (fproto, gi->gi_sw_if_index, grd->grd_table_id[fproto]);
236
237       hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool);
238     }
239
240   gi->gi_locks++;
241
242   return (gbp_itf_mk_hdl (gi));
243 }
244
245 gbp_itf_hdl_t
246 gbp_itf_l3_add_and_lock (u32 sw_if_index, index_t gri)
247 {
248   return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, NULL));
249 }
250
251 gbp_itf_hdl_t
252 gbp_itf_l3_add_and_lock_w_free (u32 sw_if_index,
253                                 index_t gri, gbp_itf_free_fn_t ff)
254 {
255   return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, ff));
256 }
257
258 void
259 gbp_itf_lock (gbp_itf_hdl_t gh)
260 {
261   gbp_itf_t *gi;
262
263   if (!gbp_itf_hdl_is_valid (gh))
264     return;
265
266   gi = gbp_itf_find_hdl (gh);
267
268   gi->gi_locks++;
269 }
270
271 gbp_itf_hdl_t
272 gbp_itf_clone_and_lock (gbp_itf_hdl_t gh)
273 {
274   gbp_itf_t *gi;
275
276   if (!gbp_itf_hdl_is_valid (gh))
277     return (GBP_ITF_HDL_INVALID);
278
279   gi = gbp_itf_find_hdl (gh);
280
281   gi->gi_locks++;
282
283   return (gbp_itf_mk_hdl (gi));
284 }
285
286 void
287 gbp_itf_unlock (gbp_itf_hdl_t * gh)
288 {
289   gbp_itf_t *gi;
290
291   if (!gbp_itf_hdl_is_valid (*gh))
292     return;
293
294   gi = gbp_itf_find_hdl (*gh);
295   ASSERT (gi->gi_locks > 0);
296   gi->gi_locks--;
297
298   if (0 == gi->gi_locks)
299     {
300       if (GBP_ITF_MODE_L2 == gi->gi_mode)
301         {
302           gbp_itf_l2_set_input_feature (*gh, L2INPUT_FEAT_NONE);
303           gbp_itf_l2_set_output_feature (*gh, L2OUTPUT_FEAT_NONE);
304           gbp_bridge_domain_itf_del (gi->gi_gbi,
305                                      gi->gi_sw_if_index,
306                                      L2_BD_PORT_TYPE_NORMAL);
307         }
308       else
309         {
310           fib_protocol_t fproto;
311
312           gbp_itf_l3_set_input_feature (*gh, GBP_ITF_L3_FEAT_NONE);
313           FOR_EACH_FIB_IP_PROTOCOL (fproto)
314           ip_table_bind (fproto, gi->gi_sw_if_index, 0);
315
316           ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 0);
317           ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 0);
318         }
319
320       hash_unset (gbp_itf_db, gi->gi_sw_if_index);
321
322       if (gi->gi_free_fn)
323         gi->gi_free_fn (gi->gi_sw_if_index);
324
325       pool_free (gi->gi_users);
326       vec_free (gi->gi_input_fbs);
327       vec_free (gi->gi_output_fbs);
328
329       memset (gi, 0, sizeof (*gi));
330     }
331
332   gbp_itf_hdl_reset (gh);
333 }
334
335 void
336 gbp_itf_l3_set_input_feature (gbp_itf_hdl_t gh, gbp_itf_l3_feat_t feats)
337 {
338   u32 diff_fb, new_fb, *fb, feat;
339   gbp_itf_t *gi;
340
341   gi = gbp_itf_find_hdl (gh);
342
343   if (NULL == gi || GBP_ITF_MODE_L3 != gi->gi_mode)
344     return;
345
346   vec_validate (gi->gi_input_fbs, gh.gh_who);
347   gi->gi_input_fbs[gh.gh_who] = feats;
348
349   new_fb = 0;
350   vec_foreach (fb, gi->gi_input_fbs)
351   {
352     new_fb |= *fb;
353   }
354
355   /* add new features */
356   diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb;
357
358   /* *INDENT-OFF* */
359   foreach_set_bit (feat, diff_fb,
360   ({
361     vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat],
362                                  gbp_itf_feat_bit_pos_to_feat[feat],
363                                  gi->gi_sw_if_index, 1, 0, 0);
364   }));
365   /* *INDENT-ON* */
366
367   /* remove unneeded features */
368   diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb;
369
370   /* *INDENT-OFF* */
371   foreach_set_bit (feat, diff_fb,
372   ({
373     vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat],
374                                  gbp_itf_feat_bit_pos_to_feat[feat],
375                                  gi->gi_sw_if_index, 0, 0, 0);
376   }));
377   /* *INDENT-ON* */
378
379   gi->gi_input_fb = new_fb;
380 }
381
382 void
383 gbp_itf_l2_set_input_feature (gbp_itf_hdl_t gh, l2input_feat_masks_t feats)
384 {
385   u32 diff_fb, new_fb, *fb, feat;
386   gbp_itf_t *gi;
387
388   gi = gbp_itf_find_hdl (gh);
389
390   if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode)
391     {
392       ASSERT (0);
393       return;
394     }
395
396   vec_validate (gi->gi_input_fbs, gh.gh_who);
397   gi->gi_input_fbs[gh.gh_who] = feats;
398
399   new_fb = 0;
400   vec_foreach (fb, gi->gi_input_fbs)
401   {
402     new_fb |= *fb;
403   }
404
405   /* add new features */
406   diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb;
407
408   /* *INDENT-OFF* */
409   foreach_set_bit (feat, diff_fb,
410   ({
411     l2input_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 1);
412   }));
413   /* *INDENT-ON* */
414
415   /* remove unneeded features */
416   diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb;
417
418   /* *INDENT-OFF* */
419   foreach_set_bit (feat, diff_fb,
420   ({
421     l2input_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 0);
422   }));
423   /* *INDENT-ON* */
424
425   gi->gi_input_fb = new_fb;
426 }
427
428 void
429 gbp_itf_l2_set_output_feature (gbp_itf_hdl_t gh, l2output_feat_masks_t feats)
430 {
431   u32 diff_fb, new_fb, *fb, feat;
432   gbp_itf_t *gi;
433
434   gi = gbp_itf_find_hdl (gh);
435
436   if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode)
437     {
438       ASSERT (0);
439       return;
440     }
441
442   vec_validate (gi->gi_output_fbs, gh.gh_who);
443   gi->gi_output_fbs[gh.gh_who] = feats;
444
445   new_fb = 0;
446   vec_foreach (fb, gi->gi_output_fbs)
447   {
448     new_fb |= *fb;
449   }
450
451   /* add new features */
452   diff_fb = (gi->gi_output_fb ^ new_fb) & new_fb;
453
454   /* *INDENT-OFF* */
455   foreach_set_bit (feat, diff_fb,
456   ({
457     l2output_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 1);
458   }));
459   /* *INDENT-ON* */
460
461   /* remove unneeded features */
462   diff_fb = (gi->gi_output_fb ^ new_fb) & gi->gi_output_fb;
463
464   /* *INDENT-OFF* */
465   foreach_set_bit (feat, diff_fb,
466   ({
467     l2output_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 0);
468   }));
469   /* *INDENT-ON* */
470
471   gi->gi_output_fb = new_fb;
472 }
473
474 static u8 *
475 format_gbp_itf_mode (u8 * s, va_list * args)
476 {
477   gbp_itf_mode_t mode = va_arg (*args, gbp_itf_mode_t);
478
479   switch (mode)
480     {
481 #define _(a,v)                                  \
482     case GBP_ITF_MODE_##a:                      \
483       return format(s, "%s", v);
484       foreach_gbp_itf_mode
485 #undef _
486     }
487   return (s);
488 }
489
490 static u8 *
491 format_gbp_itf (u8 * s, va_list * args)
492 {
493   index_t gii = va_arg (*args, index_t);
494   gbp_itf_t *gi;
495
496   if (INDEX_INVALID == gii)
497     return (format (s, "unset"));
498
499   gi = gbp_itf_get (gii);
500
501   s = format (s, "%U locks:%d mode:%U ",
502               format_vnet_sw_if_index_name, vnet_get_main (),
503               gi->gi_sw_if_index, gi->gi_locks,
504               format_gbp_itf_mode, gi->gi_mode);
505
506   if (GBP_ITF_MODE_L2 == gi->gi_mode)
507     s = format (s, "gbp-bd:%d input-feats:[%U] output-feats:[%U]",
508                 gi->gi_gbi,
509                 format_l2_input_features, gi->gi_input_fb, 0,
510                 format_l2_output_features, gi->gi_output_fb, 0);
511   else
512     s = format (s, "gbp-rd:%d input-feats:[%U] output-feats:[%U]",
513                 gi->gi_gbi,
514                 format_gbp_itf_l3_feat, gi->gi_input_fb,
515                 format_gbp_itf_l3_feat, gi->gi_output_fb);
516
517   return (s);
518 }
519
520 u8 *
521 format_gbp_itf_hdl (u8 * s, va_list * args)
522 {
523   gbp_itf_hdl_t gh = va_arg (*args, gbp_itf_hdl_t);
524   gbp_itf_t *gi;
525
526   gi = gbp_itf_find_hdl (gh);
527
528   if (NULL == gi)
529     return format (s, "INVALID");
530
531   return (format (s, "%U", format_gbp_itf, gi - gbp_itf_pool));
532 }
533
534 static clib_error_t *
535 gbp_itf_show (vlib_main_t * vm,
536               unformat_input_t * input, vlib_cli_command_t * cmd)
537 {
538   u32 gii;
539
540   vlib_cli_output (vm, "Interfaces:");
541
542   /* *INDENT-OFF* */
543   pool_foreach_index (gii, gbp_itf_pool)
544    {
545     vlib_cli_output (vm, "  [%d] %U", gii, format_gbp_itf, gii);
546   }
547   /* *INDENT-ON* */
548
549   return (NULL);
550 }
551
552 /*?
553  * Show Group Based Interfaces
554  *
555  * @cliexpar
556  * @cliexstart{show gbp contract}
557  * @cliexend
558  ?*/
559 /* *INDENT-OFF* */
560 VLIB_CLI_COMMAND (gbp_contract_show_node, static) = {
561   .path = "show gbp interface",
562   .short_help = "show gbp interface\n",
563   .function = gbp_itf_show,
564 };
565 /* *INDENT-ON* */
566
567
568 /*
569  * fd.io coding-style-patch-verification: ON
570  *
571  * Local Variables:
572  * eval: (c-set-style "gnu")
573  * End:
574  */