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