ip: use IPv6 flowlabel in flow hash computation
[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 #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,
236                        grd->grd_table_id[fproto], 1);
237
238       hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool);
239     }
240
241   gi->gi_locks++;
242
243   return (gbp_itf_mk_hdl (gi));
244 }
245
246 gbp_itf_hdl_t
247 gbp_itf_l3_add_and_lock (u32 sw_if_index, index_t gri)
248 {
249   return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, NULL));
250 }
251
252 gbp_itf_hdl_t
253 gbp_itf_l3_add_and_lock_w_free (u32 sw_if_index,
254                                 index_t gri, gbp_itf_free_fn_t ff)
255 {
256   return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, ff));
257 }
258
259 void
260 gbp_itf_lock (gbp_itf_hdl_t gh)
261 {
262   gbp_itf_t *gi;
263
264   if (!gbp_itf_hdl_is_valid (gh))
265     return;
266
267   gi = gbp_itf_find_hdl (gh);
268
269   gi->gi_locks++;
270 }
271
272 gbp_itf_hdl_t
273 gbp_itf_clone_and_lock (gbp_itf_hdl_t gh)
274 {
275   gbp_itf_t *gi;
276
277   if (!gbp_itf_hdl_is_valid (gh))
278     return (GBP_ITF_HDL_INVALID);
279
280   gi = gbp_itf_find_hdl (gh);
281
282   gi->gi_locks++;
283
284   return (gbp_itf_mk_hdl (gi));
285 }
286
287 void
288 gbp_itf_unlock (gbp_itf_hdl_t * gh)
289 {
290   gbp_itf_t *gi;
291
292   if (!gbp_itf_hdl_is_valid (*gh))
293     return;
294
295   gi = gbp_itf_find_hdl (*gh);
296   ASSERT (gi->gi_locks > 0);
297   gi->gi_locks--;
298
299   if (0 == gi->gi_locks)
300     {
301       if (GBP_ITF_MODE_L2 == gi->gi_mode)
302         {
303           gbp_itf_l2_set_input_feature (*gh, L2INPUT_FEAT_NONE);
304           gbp_itf_l2_set_output_feature (*gh, L2OUTPUT_FEAT_NONE);
305           gbp_bridge_domain_itf_del (gi->gi_gbi,
306                                      gi->gi_sw_if_index,
307                                      L2_BD_PORT_TYPE_NORMAL);
308         }
309       else
310         {
311           fib_protocol_t fproto;
312
313           gbp_itf_l3_set_input_feature (*gh, GBP_ITF_L3_FEAT_NONE);
314           FOR_EACH_FIB_IP_PROTOCOL (fproto)
315             ip_table_bind (fproto, gi->gi_sw_if_index, 0, 0);
316
317           ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 0);
318           ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 0);
319         }
320
321       hash_unset (gbp_itf_db, gi->gi_sw_if_index);
322
323       if (gi->gi_free_fn)
324         gi->gi_free_fn (gi->gi_sw_if_index);
325
326       pool_free (gi->gi_users);
327       vec_free (gi->gi_input_fbs);
328       vec_free (gi->gi_output_fbs);
329
330       memset (gi, 0, sizeof (*gi));
331     }
332
333   gbp_itf_hdl_reset (gh);
334 }
335
336 void
337 gbp_itf_l3_set_input_feature (gbp_itf_hdl_t gh, gbp_itf_l3_feat_t feats)
338 {
339   u32 diff_fb, new_fb, *fb, feat;
340   gbp_itf_t *gi;
341
342   gi = gbp_itf_find_hdl (gh);
343
344   if (NULL == gi || GBP_ITF_MODE_L3 != gi->gi_mode)
345     return;
346
347   vec_validate (gi->gi_input_fbs, gh.gh_who);
348   gi->gi_input_fbs[gh.gh_who] = feats;
349
350   new_fb = 0;
351   vec_foreach (fb, gi->gi_input_fbs)
352   {
353     new_fb |= *fb;
354   }
355
356   /* add new features */
357   diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb;
358
359   /* *INDENT-OFF* */
360   foreach_set_bit (feat, diff_fb,
361   ({
362     vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat],
363                                  gbp_itf_feat_bit_pos_to_feat[feat],
364                                  gi->gi_sw_if_index, 1, 0, 0);
365   }));
366   /* *INDENT-ON* */
367
368   /* remove unneeded features */
369   diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb;
370
371   /* *INDENT-OFF* */
372   foreach_set_bit (feat, diff_fb,
373   ({
374     vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat],
375                                  gbp_itf_feat_bit_pos_to_feat[feat],
376                                  gi->gi_sw_if_index, 0, 0, 0);
377   }));
378   /* *INDENT-ON* */
379
380   gi->gi_input_fb = new_fb;
381 }
382
383 void
384 gbp_itf_l2_set_input_feature (gbp_itf_hdl_t gh, l2input_feat_masks_t feats)
385 {
386   u32 diff_fb, new_fb, *fb, feat;
387   gbp_itf_t *gi;
388
389   gi = gbp_itf_find_hdl (gh);
390
391   if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode)
392     {
393       ASSERT (0);
394       return;
395     }
396
397   vec_validate (gi->gi_input_fbs, gh.gh_who);
398   gi->gi_input_fbs[gh.gh_who] = feats;
399
400   new_fb = 0;
401   vec_foreach (fb, gi->gi_input_fbs)
402   {
403     new_fb |= *fb;
404   }
405
406   /* add new features */
407   diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb;
408
409   /* *INDENT-OFF* */
410   foreach_set_bit (feat, diff_fb,
411   ({
412     l2input_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 1);
413   }));
414   /* *INDENT-ON* */
415
416   /* remove unneeded features */
417   diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb;
418
419   /* *INDENT-OFF* */
420   foreach_set_bit (feat, diff_fb,
421   ({
422     l2input_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 0);
423   }));
424   /* *INDENT-ON* */
425
426   gi->gi_input_fb = new_fb;
427 }
428
429 void
430 gbp_itf_l2_set_output_feature (gbp_itf_hdl_t gh, l2output_feat_masks_t feats)
431 {
432   u32 diff_fb, new_fb, *fb, feat;
433   gbp_itf_t *gi;
434
435   gi = gbp_itf_find_hdl (gh);
436
437   if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode)
438     {
439       ASSERT (0);
440       return;
441     }
442
443   vec_validate (gi->gi_output_fbs, gh.gh_who);
444   gi->gi_output_fbs[gh.gh_who] = feats;
445
446   new_fb = 0;
447   vec_foreach (fb, gi->gi_output_fbs)
448   {
449     new_fb |= *fb;
450   }
451
452   /* add new features */
453   diff_fb = (gi->gi_output_fb ^ new_fb) & new_fb;
454
455   /* *INDENT-OFF* */
456   foreach_set_bit (feat, diff_fb,
457   ({
458     l2output_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 1);
459   }));
460   /* *INDENT-ON* */
461
462   /* remove unneeded features */
463   diff_fb = (gi->gi_output_fb ^ new_fb) & gi->gi_output_fb;
464
465   /* *INDENT-OFF* */
466   foreach_set_bit (feat, diff_fb,
467   ({
468     l2output_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 0);
469   }));
470   /* *INDENT-ON* */
471
472   gi->gi_output_fb = new_fb;
473 }
474
475 static u8 *
476 format_gbp_itf_mode (u8 * s, va_list * args)
477 {
478   gbp_itf_mode_t mode = va_arg (*args, gbp_itf_mode_t);
479
480   switch (mode)
481     {
482 #define _(a,v)                                  \
483     case GBP_ITF_MODE_##a:                      \
484       return format(s, "%s", v);
485       foreach_gbp_itf_mode
486 #undef _
487     }
488   return (s);
489 }
490
491 static u8 *
492 format_gbp_itf (u8 * s, va_list * args)
493 {
494   index_t gii = va_arg (*args, index_t);
495   gbp_itf_t *gi;
496
497   if (INDEX_INVALID == gii)
498     return (format (s, "unset"));
499
500   gi = gbp_itf_get (gii);
501
502   s = format (s, "%U locks:%d mode:%U ",
503               format_vnet_sw_if_index_name, vnet_get_main (),
504               gi->gi_sw_if_index, gi->gi_locks,
505               format_gbp_itf_mode, gi->gi_mode);
506
507   if (GBP_ITF_MODE_L2 == gi->gi_mode)
508     s = format (s, "gbp-bd:%d input-feats:[%U] output-feats:[%U]",
509                 gi->gi_gbi,
510                 format_l2_input_features, gi->gi_input_fb, 0,
511                 format_l2_output_features, gi->gi_output_fb, 0);
512   else
513     s = format (s, "gbp-rd:%d input-feats:[%U] output-feats:[%U]",
514                 gi->gi_gbi,
515                 format_gbp_itf_l3_feat, gi->gi_input_fb,
516                 format_gbp_itf_l3_feat, gi->gi_output_fb);
517
518   return (s);
519 }
520
521 u8 *
522 format_gbp_itf_hdl (u8 * s, va_list * args)
523 {
524   gbp_itf_hdl_t gh = va_arg (*args, gbp_itf_hdl_t);
525   gbp_itf_t *gi;
526
527   gi = gbp_itf_find_hdl (gh);
528
529   if (NULL == gi)
530     return format (s, "INVALID");
531
532   return (format (s, "%U", format_gbp_itf, gi - gbp_itf_pool));
533 }
534
535 static clib_error_t *
536 gbp_itf_show (vlib_main_t * vm,
537               unformat_input_t * input, vlib_cli_command_t * cmd)
538 {
539   u32 gii;
540
541   vlib_cli_output (vm, "Interfaces:");
542
543   /* *INDENT-OFF* */
544   pool_foreach_index (gii, gbp_itf_pool)
545    {
546     vlib_cli_output (vm, "  [%d] %U", gii, format_gbp_itf, gii);
547   }
548   /* *INDENT-ON* */
549
550   return (NULL);
551 }
552
553 /*?
554  * Show Group Based Interfaces
555  *
556  * @cliexpar
557  * @cliexstart{show gbp contract}
558  * @cliexend
559  ?*/
560 /* *INDENT-OFF* */
561 VLIB_CLI_COMMAND (gbp_contract_show_node, static) = {
562   .path = "show gbp interface",
563   .short_help = "show gbp interface\n",
564   .function = gbp_itf_show,
565 };
566 /* *INDENT-ON* */
567
568
569 /*
570  * fd.io coding-style-patch-verification: ON
571  *
572  * Local Variables:
573  * eval: (c-set-style "gnu")
574  * End:
575  */