FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
l2_fib.c
Go to the documentation of this file.
1 /*
2  * l2_fib.c : layer 2 forwarding table (aka mac table)
3  *
4  * Copyright (c) 2013 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 
19 #include <vlib/vlib.h>
20 #include <vnet/vnet.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vlib/cli.h>
23 
24 #include <vppinfra/error.h>
25 #include <vppinfra/hash.h>
26 #include <vnet/l2/l2_input.h>
27 #include <vnet/l2/l2_fib.h>
28 #include <vnet/l2/l2_learn.h>
29 #include <vnet/l2/l2_bd.h>
31 #include <vlibmemory/api.h>
32 
33 #include <vnet/l2/l2.api_enum.h>
34 #include <vnet/l2/l2.api_types.h>
35 
36 #define vl_endianfun
37 #include <vnet/l2/l2.api.h>
38 #undef vl_endianfun
39 
40 /**
41  * @file
42  * @brief Ethernet MAC Address FIB Table Management.
43  *
44  * The MAC Address forwarding table for bridge-domains is called the l2fib.
45  * Entries are added automatically as part of mac learning, but MAC Addresses
46  * entries can also be added manually.
47  *
48  */
49 
51 
52 u8 *
53 format_l2fib_entry_result_flags (u8 * s, va_list * args)
54 {
55  l2fib_entry_result_flags_t flags = va_arg (*args, int);
56 
58  {
59  s = format (s, "none");
60  }
61  else
62  {
63 #define _(a,v,t) { \
64  if (flags & L2FIB_ENTRY_RESULT_FLAG_##a) \
65  s = format (s, "%s ", t); \
66  }
68 #undef _
69  }
70  return (s);
71 }
72 
73 static void
75 {
76  u64 tmp = *((u64 *) mac);
77  tmp = clib_net_to_host_u64 (tmp);
78  tmp += 1 << 16; /* skip unused (least significant) octets */
79  tmp = clib_host_to_net_u64 (tmp);
80 
81  clib_memcpy_fast (mac, &tmp, 6);
82 }
83 
84 /** Format sw_if_index. If the value is ~0, use the text "N/A" */
85 u8 *
87 {
88  vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
89  u32 sw_if_index = va_arg (*args, u32);
90  if (sw_if_index == ~0)
91  return format (s, "N/A");
92 
95  if (!swif)
96  return format (s, "Stale");
97 
98  return format (s, "%U", format_vnet_sw_interface_name, vnm,
100 }
101 
103 {
108 
109 static int
110 l2fib_dump_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
111 {
112  l2fib_dump_walk_ctx_t *ctx = arg;
113  l2fib_entry_result_t result;
115 
116  key.raw = kvp->key;
117  result.raw = kvp->value;
118 
119  if ((ctx->bd_index == ~0) || (ctx->bd_index == key.fields.bd_index))
120  {
121  vec_add1 (ctx->l2fe_key, key);
122  vec_add1 (ctx->l2fe_res, result);
123  }
124 
125  return (BIHASH_WALK_CONTINUE);
126 }
127 
128 void
130  l2fib_entry_key_t ** l2fe_key,
131  l2fib_entry_result_t ** l2fe_res)
132 {
133  l2fib_main_t *msm = &l2fib_main;
135  .bd_index = bd_index,
136  };
137 
139  (&msm->mac_table, l2fib_dump_walk_cb, &ctx);
140 
141  *l2fe_key = ctx.l2fe_key;
142  *l2fe_res = ctx.l2fe_res;
143 }
144 
145 void
147 {
148  *bd_sn = sn >> 8;
149  *if_sn = sn & 0xff;
150 }
151 
152 u8 *
153 format_l2_fib_seq_num (u8 * s, va_list * a)
154 {
155  l2fib_seq_num_t sn = va_arg (*a, int);
156  u8 bd_sn, if_sn;
157 
158  l2_fib_extract_seq_num (sn, &bd_sn, &if_sn);
159 
160  s = format (s, "%3d/%-3d", bd_sn, if_sn);
161 
162  return (s);
163 }
164 
166 {
177 
178 static int
179 l2fib_show_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
180 {
181  l2fib_show_walk_ctx_t *ctx = arg;
182  l2_bridge_domain_t *bd_config;
183  l2fib_entry_result_t result;
185 
186  if (ctx->verbose && ctx->first_entry)
187  {
188  ctx->first_entry = 0;
189  vlib_cli_output (ctx->vm,
190  "%=19s%=7s%=7s%=8s%=9s%=7s%=7s%=5s%=30s",
191  "Mac-Address", "BD-Idx", "If-Idx",
192  "BSN-ISN", "Age(min)", "static", "filter",
193  "bvi", "Interface-Name");
194  }
195 
196  key.raw = kvp->key;
197  result.raw = kvp->value;
198  ctx->total_entries++;
199 
200  if (ctx->verbose &&
201  ((ctx->bd_index >> 31) || (ctx->bd_index == key.fields.bd_index)))
202  {
203  u8 *s = NULL;
204 
205  if (ctx->learn && l2fib_entry_result_is_set_AGE_NOT (&result))
206  return (BIHASH_WALK_CONTINUE); /* skip provisioned macs */
207 
208  if (ctx->add && !l2fib_entry_result_is_set_AGE_NOT (&result))
209  return (BIHASH_WALK_CONTINUE); /* skip learned macs */
210 
211  bd_config = &vec_elt (l2input_main.bd_configs, key.fields.bd_index);
212 
213  if (l2fib_entry_result_is_set_AGE_NOT (&result))
214  s = format (s, "no");
215  else if (bd_config->mac_age == 0)
216  s = format (s, "-");
217  else
218  {
219  i16 delta = ctx->now - result.fields.timestamp;
220  delta += delta < 0 ? 256 : 0;
221  s = format (s, "%d", delta);
222  }
223 
224  vlib_cli_output (ctx->vm,
225  "%=19U%=7d%=7d %U%=9v%=7s%=7s%=5s%=30U",
226  format_ethernet_address, key.fields.mac,
227  key.fields.bd_index,
228  result.fields.sw_if_index == ~0
229  ? -1 : result.fields.sw_if_index,
230  format_l2_fib_seq_num, result.fields.sn, s,
231  l2fib_entry_result_is_set_STATIC (&result) ? "*" : "-",
232  l2fib_entry_result_is_set_FILTER (&result) ? "*" : "-",
233  l2fib_entry_result_is_set_BVI (&result) ? "*" : "-",
235  ctx->vnm, result.fields.sw_if_index);
236  vec_free (s);
237  }
238 
239  return (BIHASH_WALK_CONTINUE);
240 }
241 
242 /** Display the contents of the l2fib. */
243 static clib_error_t *
245  unformat_input_t * input, vlib_cli_command_t * cmd)
246 {
247  bd_main_t *bdm = &bd_main;
248  l2fib_main_t *msm = &l2fib_main;
249  u8 raw = 0;
250  u32 bd_id;
252  .first_entry = 1,
253  .bd_index = ~0,
254  .now = (u8) (vlib_time_now (vm) / 60),
255  .vm = vm,
256  .vnm = msm->vnet_main,
257  };
258 
260  {
261  if (unformat (input, "raw"))
262  {
263  raw = 1;
264  ctx.verbose = 0;
265  break;
266  }
267  else if (unformat (input, "verbose"))
268  ctx.verbose = 1;
269  else if (unformat (input, "all"))
270  ctx.verbose = 1;
271  else if (unformat (input, "bd_index %d", &ctx.bd_index))
272  ctx.verbose = 1;
273  else if (unformat (input, "learn"))
274  {
275  ctx.add = 0;
276  ctx.learn = 1;
277  ctx.verbose = 1;
278  }
279  else if (unformat (input, "add"))
280  {
281  ctx.learn = 0;
282  ctx.add = 1;
283  ctx.verbose = 1;
284  }
285  else if (unformat (input, "bd_id %d", &bd_id))
286  {
287  uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
288  if (p)
289  {
290  ctx.verbose = 1;
291  ctx.bd_index = p[0];
292  }
293  else
294  return clib_error_return (0,
295  "bridge domain id %d doesn't exist\n",
296  bd_id);
297  }
298  else
299  break;
300  }
301 
302  if (msm->mac_table_initialized == 0)
303  {
304  vlib_cli_output (vm, "no l2fib entries");
305  return 0;
306  }
307 
309  (&msm->mac_table, l2fib_show_walk_cb, &ctx);
310 
311  if (ctx.total_entries == 0)
312  vlib_cli_output (vm, "no l2fib entries");
313  else
314  {
316  vlib_cli_output (vm, "L2FIB total/learned entries: %d/%d "
317  "Last scan time: %.4esec Learn limit: %d ",
318  ctx.total_entries, lm->global_learn_count,
320  if (lm->client_pid)
321  vlib_cli_output (vm, "L2MAC events client PID: %d "
322  "Last e-scan time: %.4esec Delay: %.2esec "
323  "Max macs in event: %d",
324  lm->client_pid, msm->evt_scan_duration,
326  }
327 
328  if (raw)
329  vlib_cli_output (vm, "Raw Hash Table:\n%U\n",
330  BV (format_bihash), &msm->mac_table, 1 /* verbose */ );
331 
332  return 0;
333 }
334 
335 /*?
336  * This command displays the MAC Address entries of the L2 FIB table.
337  * Output can be filtered to just get the number of MAC Addresses or display
338  * each MAC Address for all bridge domains or just a single bridge domain.
339  *
340  * @cliexpar
341  * Example of how to display the number of MAC Address entries in the L2
342  * FIB table:
343  * @cliexstart{show l2fib}
344  * 3 l2fib entries
345  * @cliexend
346  * Example of how to display all the MAC Address entries in the L2
347  * FIB table:
348  * @cliexstart{show l2fib all}
349  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
350  * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
351  * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
352  * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
353  * 3 l2fib entries
354  * @cliexend
355 ?*/
356 /* *INDENT-OFF* */
358  .path = "show l2fib",
359  .short_help = "show l2fib [all] | [bd_id <nn> | bd_index <nn>] [learn | add] | [raw]",
360  .function = show_l2fib,
361 };
362 /* *INDENT-ON* */
363 
364 void
366 {
367  l2fib_main_t *mp = &l2fib_main;
368 
369  if (mp->mac_table_initialized == 1)
370  return;
371 
372  BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
374  mp->mac_table_initialized = 1;
375 }
376 
377 /* Remove all entries from the l2fib */
378 void
380 {
381  l2fib_main_t *mp = &l2fib_main;
382  l2_bridge_domain_t *bd_config;
383 
384  if (mp->mac_table_initialized == 0)
385  return;
386 
387  mp->mac_table_initialized = 0;
388 
389  /* Remove all entries */
390  BV (clib_bihash_free) (&mp->mac_table);
391  l2fib_table_init ();
393  vec_foreach (bd_config, l2input_main.bd_configs)
394  bd_config->learn_count = 0;
395 }
396 
397 /** Clear all entries in L2FIB.
398  * @TODO: Later we may want a way to remove only the non-static entries
399  */
400 static clib_error_t *
402  unformat_input_t * input, vlib_cli_command_t * cmd)
403 {
405  return 0;
406 }
407 
408 /*?
409  * This command clears all the MAC Address entries from the L2 FIB table.
410  *
411  * @cliexpar
412  * Example of how to clear the L2 FIB Table:
413  * @cliexcmd{clear l2fib}
414  * Example to show the L2 FIB Table has been cleared:
415  * @cliexstart{show l2fib verbose}
416  * no l2fib entries
417  * @cliexend
418 ?*/
419 /* *INDENT-OFF* */
421  .path = "clear l2fib",
422  .short_help = "clear l2fib",
423  .function = clear_l2fib,
424 };
425 /* *INDENT-ON* */
426 
427 static l2fib_seq_num_t
429 {
430  l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
431 
432  return l2_fib_mk_seq_num (bd_config->seq_num,
434 }
435 
436 /**
437  * Add an entry to the l2fib.
438  * If the entry already exists then overwrite it
439  */
440 void
441 l2fib_add_entry (const u8 * mac, u32 bd_index,
443 {
445  l2fib_entry_result_t result;
446  __attribute__ ((unused)) u32 bucket_contents;
449  BVT (clib_bihash_kv) kv;
450 
451  if (fm->mac_table_initialized == 0)
452  l2fib_table_init ();
453 
454  /* set up key */
455  key.raw = l2fib_make_key (mac, bd_index);
456  kv.key = key.raw;
457 
458  /* check if entry already exist */
459  if (BV (clib_bihash_search) (&fm->mac_table, &kv, &kv))
460  {
461  /* decrement counter if overwriting a learned mac */
462  result.raw = kv.value;
463  if (!l2fib_entry_result_is_set_AGE_NOT (&result))
464  {
465  l2_bridge_domain_t *bd_config =
467 
468  /* check if learn_count == 0 in case of race condition between 2
469  * workers adding an entry simultaneously */
470  /* learn_count variable may have little inaccuracy because they are
471  * not incremented/decremented with atomic operations */
472  /* l2fib_scan is call every 2sec fixing potential inaccuracy */
473  if (lm->global_learn_count)
474  lm->global_learn_count--;
475  if (bd_config->learn_count)
476  bd_config->learn_count--;
477  }
478  }
479 
480  /* set up result */
481  result.raw = 0; /* clear all fields */
482  result.fields.sw_if_index = sw_if_index;
483  result.fields.flags = flags;
484 
485  /* no aging for provisioned entry */
486  l2fib_entry_result_set_AGE_NOT (&result);
487 
488  kv.value = result.raw;
489 
490  BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1 /* is_add */ );
491 }
492 
493 /**
494  * Add an entry to the L2FIB.
495  * The CLI format is:
496  * l2fib add <mac> <bd> <intf> [static] [bvi]
497  * l2fib add <mac> <bd> filter
498  * Note that filter and bvi entries are always static
499  */
500 static clib_error_t *
502  unformat_input_t * input, vlib_cli_command_t * cmd)
503 {
504  bd_main_t *bdm = &bd_main;
505  vnet_main_t *vnm = vnet_get_main ();
506  clib_error_t *error = 0;
507  u8 mac[6];
508  u32 bd_id;
509  u32 bd_index;
510  u32 sw_if_index = ~0;
511  uword *p;
513 
515 
516  if (!unformat (input, "%U", unformat_ethernet_address, mac))
517  {
518  error = clib_error_return (0, "expected mac address `%U'",
519  format_unformat_error, input);
520  goto done;
521  }
522 
523  if (!unformat (input, "%d", &bd_id))
524  {
525  error = clib_error_return (0, "expected bridge domain ID `%U'",
526  format_unformat_error, input);
527  goto done;
528  }
529 
530  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
531  if (!p)
532  {
533  error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
534  goto done;
535  }
536  bd_index = p[0];
537 
538  if (unformat (input, "filter"))
539  {
540  l2fib_add_filter_entry (mac, bd_index);
541  return 0;
542  }
543 
545  {
546  error = clib_error_return (0, "unknown interface `%U'",
547  format_unformat_error, input);
548  goto done;
549  }
550 
551  if (unformat (input, "static"))
552  flags |= L2FIB_ENTRY_RESULT_FLAG_STATIC;
553  else if (unformat (input, "bvi"))
554  flags |= (L2FIB_ENTRY_RESULT_FLAG_STATIC | L2FIB_ENTRY_RESULT_FLAG_BVI);
555 
557  {
558  error = clib_error_return (0, "Interface sw_if_index %d not in L2 mode",
559  sw_if_index);
560  goto done;
561  }
562 
563  l2fib_add_entry (mac, bd_index, sw_if_index, flags);
564 
565 done:
566  return error;
567 }
568 
569 /*?
570  * This command adds a MAC Address entry to the L2 FIB table
571  * of an existing bridge-domain. The MAC Address can be static
572  * or dynamic. This command also allows a filter to be added,
573  * such that packets with given MAC Addresses (source mac or
574  * destination mac match) are dropped.
575  *
576  * @cliexpar
577  * Example of how to add a dynamic MAC Address entry to the L2 FIB table
578  * of a bridge-domain (where 200 is the bridge-domain-id):
579  * @cliexcmd{l2fib add 52:54:00:53:18:33 200 GigabitEthernet0/8/0.200}
580  * Example of how to add a static MAC Address entry to the L2 FIB table
581  * of a bridge-domain (where 200 is the bridge-domain-id):
582  * @cliexcmd{l2fib add 52:54:00:53:18:55 200 GigabitEthernet0/8/0.200 static}
583  * Example of how to add a filter such that a packet with the given MAC
584  * Address will be dropped in a given bridge-domain (where 200 is the
585  * bridge-domain-id):
586  * @cliexcmd{l2fib add 52:54:00:53:18:77 200 filter}
587  * Example of show command of the provisioned MAC Addresses and filters:
588  * @cliexstart{show l2fib verbose}
589  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
590  * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
591  * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
592  * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
593  * 3 l2fib entries
594  * @cliexend
595 ?*/
596 /* *INDENT-OFF* */
598  .path = "l2fib add",
599  .short_help = "l2fib add <mac> <bridge-domain-id> filter | <intf> [static | bvi]",
600  .function = l2fib_add,
601 };
602 /* *INDENT-ON* */
603 
604 
605 static clib_error_t *
607  unformat_input_t * input, vlib_cli_command_t * cmd)
608 {
609  u8 mac[6], save_mac[6];
610  u32 bd_index = 0;
611  u32 sw_if_index = 8;
612  u32 is_add = 0;
613  u32 is_del = 0;
614  u32 is_check = 0;
615  u32 count = 1;
616  int mac_set = 0;
617  int i;
618 
620  {
621  if (unformat (input, "mac %U", unformat_ethernet_address, mac))
622  mac_set = 1;
623  else if (unformat (input, "add"))
624  is_add = 1;
625  else if (unformat (input, "del"))
626  is_del = 1;
627  else if (unformat (input, "check"))
628  is_check = 1;
629  else if (unformat (input, "count %d", &count))
630  ;
631  else
632  break;
633  }
634 
635  if (mac_set == 0)
636  return clib_error_return (0, "mac not set");
637 
638  if (is_add == 0 && is_del == 0 && is_check == 0)
639  return clib_error_return (0,
640  "noop: pick at least one of (add,del,check)");
641 
642  clib_memcpy_fast (save_mac, mac, 6);
643 
644  if (is_add)
645  {
646  for (i = 0; i < count; i++)
647  {
648  l2fib_add_entry (mac, bd_index, sw_if_index,
651  }
652  }
653 
654  if (is_check)
655  {
656  BVT (clib_bihash_kv) kv;
657  l2fib_main_t *mp = &l2fib_main;
658 
659  if (mp->mac_table_initialized == 0)
660  return clib_error_return (0, "mac table is not initialized");
661 
662  clib_memcpy_fast (mac, save_mac, 6);
663 
664  for (i = 0; i < count; i++)
665  {
666  kv.key = l2fib_make_key (mac, bd_index);
667  if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
668  {
669  clib_warning ("key %U AWOL", format_ethernet_address, mac);
670  break;
671  }
673  }
674  }
675 
676  if (is_del)
677  {
678  clib_memcpy_fast (mac, save_mac, 6);
679 
680  for (i = 0; i < count; i++)
681  {
682  l2fib_del_entry (mac, bd_index, 0);
684  }
685  }
686 
687  return 0;
688 }
689 
690 /*?
691  * The set of '<em>test l2fib</em>' commands allow the L2 FIB table of the default
692  * bridge domain (bridge-domain-id of 0) to be modified.
693  *
694  * @cliexpar
695  * @parblock
696  * Example of how to add a set of 4 sequential MAC Address entries to L2
697  * FIB table of the default bridge-domain:
698  * @cliexcmd{test l2fib add mac 52:54:00:53:00:00 count 4}
699  *
700  * Show the set of 4 sequential MAC Address entries that were added:
701  * @cliexstart{show l2fib verbose}
702  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
703  * 52:54:00:53:00:00 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
704  * 52:54:00:53:00:01 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
705  * 52:54:00:53:00:03 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
706  * 52:54:00:53:00:02 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
707  * 4 l2fib entries
708  * @cliexend
709  *
710  * Example of how to check that the set of 4 sequential MAC Address
711  * entries were added to L2 FIB table of the default
712  * bridge-domain. Used a count of 5 to produce an error:
713  *
714  * @cliexcmd{test l2fib check mac 52:54:00:53:00:00 count 5}
715  * The output of the check command is in the log files. Log file
716  * location may vary based on your OS and Version:
717  *
718  * <b><em># tail -f /var/log/messages | grep l2fib_test_command_fn</em></b>
719  *
720  * Sep 7 17:15:24 localhost vnet[4952]: l2fib_test_command_fn:446: key 52:54:00:53:00:04 AWOL
721  *
722  * Example of how to delete a set of 4 sequential MAC Address entries
723  * from L2 FIB table of the default bridge-domain:
724  * @cliexcmd{test l2fib del mac 52:54:00:53:00:00 count 4}
725  * @endparblock
726 ?*/
727 /* *INDENT-OFF* */
729  .path = "test l2fib",
730  .short_help = "test l2fib [add|del|check] mac <base-addr> count <nn>",
731  .function = l2fib_test_command_fn,
732 };
733 /* *INDENT-ON* */
734 
735 
736 /**
737  * Delete an entry from the l2fib.
738  * Return 0 if the entry was deleted, or 1 it was not found or if
739  * sw_if_index is non-zero and does not match that in the entry.
740  */
741 u32
742 l2fib_del_entry (const u8 * mac, u32 bd_index, u32 sw_if_index)
743 {
744  l2fib_entry_result_t result;
745  l2fib_main_t *mp = &l2fib_main;
746  BVT (clib_bihash_kv) kv;
747 
748  if (mp->mac_table_initialized == 0)
749  return 1;
750 
751  /* set up key */
752  kv.key = l2fib_make_key (mac, bd_index);
753 
754  if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
755  return 1;
756 
757  result.raw = kv.value;
758 
759  /* check if sw_if_index of entry match */
760  if ((sw_if_index != 0) && (sw_if_index != result.fields.sw_if_index))
761  return 1;
762 
763  /* decrement counter if dynamically learned mac */
764  if (!l2fib_entry_result_is_set_AGE_NOT (&result))
765  {
766  l2_bridge_domain_t *bd_config =
770  if (bd_config->learn_count)
771  bd_config->learn_count--;
772  }
773 
774  /* Remove entry from hash table */
775  BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ );
776  return 0;
777 }
778 
779 /**
780  * Delete an entry from the L2FIB.
781  * The CLI format is:
782  * l2fib del <mac> <bd-id>
783  */
784 static clib_error_t *
786  unformat_input_t * input, vlib_cli_command_t * cmd)
787 {
788  bd_main_t *bdm = &bd_main;
789  clib_error_t *error = 0;
790  u8 mac[6];
791  u32 bd_id;
792  u32 bd_index;
793  uword *p;
794 
795  if (!unformat (input, "%U", unformat_ethernet_address, mac))
796  {
797  error = clib_error_return (0, "expected mac address `%U'",
798  format_unformat_error, input);
799  goto done;
800  }
801 
802  if (!unformat (input, "%d", &bd_id))
803  {
804  error = clib_error_return (0, "expected bridge domain ID `%U'",
805  format_unformat_error, input);
806  goto done;
807  }
808 
809  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
810  if (!p)
811  {
812  error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
813  goto done;
814  }
815  bd_index = p[0];
816 
817  /* Delete the entry */
818  if (l2fib_del_entry (mac, bd_index, 0))
819  {
820  error = clib_error_return (0, "mac entry not found");
821  goto done;
822  }
823 
824 done:
825  return error;
826 }
827 
828 /*?
829  * This command deletes an existing MAC Address entry from the L2 FIB
830  * table of an existing bridge-domain.
831  *
832  * @cliexpar
833  * Example of how to delete a MAC Address entry from the L2 FIB table of a bridge-domain (where 200 is the bridge-domain-id):
834  * @cliexcmd{l2fib del 52:54:00:53:18:33 200}
835 ?*/
836 /* *INDENT-OFF* */
838  .path = "l2fib del",
839  .short_help = "l2fib del <mac> <bridge-domain-id> []",
840  .function = l2fib_del,
841 };
842 /* *INDENT-ON* */
843 
844 static clib_error_t *
846  vlib_cli_command_t *cmd)
847 {
848  clib_error_t *error = 0;
849  u32 scan_delay;
851 
852  if (!unformat (input, "%d", &scan_delay))
853  {
854  error = clib_error_return (0, "expecting delay but got `%U'",
855  format_unformat_error, input);
856  goto done;
857  }
858  fm->event_scan_delay = (f64) (scan_delay) *10e-3;
860 done:
861  return error;
862 }
863 
864 /*?
865  * This command set scan delay (in 1/10s unit)
866  *
867 ?*/
869  .path = "set l2fib scan-delay",
870  .short_help = "set l2fib scan-delay <delay>",
871  .function = l2fib_set_scan_delay,
872 };
873 
874 /**
875  Kick off ager to scan MACs to age/delete MAC entries
876 */
877 void
879 {
881 
882  /* check if there is at least one bd with mac aging enabled */
883  l2_bridge_domain_t *bd_config;
884  vec_foreach (bd_config, l2input_main.bd_configs)
885  {
886  if (bd_config->bd_id != ~0 && bd_config->mac_age != 0)
887  {
889  break;
890  }
891  }
892 
894  evt, 0);
895 }
896 
897 /**
898  Flush all non static MACs from an interface
899 */
900 void
902 {
905 }
906 
907 /**
908  Flush all non static MACs in a bridge domain
909 */
910 void
912 {
913  l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
914  bd_config->seq_num += 1;
916 }
917 
918 /**
919  Flush all non static MACs - flushes all valid BDs
920 */
921 void
923 {
924  l2_bridge_domain_t *bd_config;
925  vec_foreach (bd_config, l2input_main.bd_configs)
926  if (bd_is_valid (bd_config))
927  bd_config->seq_num += 1;
928 
930 }
931 
932 
933 /**
934  Flush MACs, except static ones, associated with an interface
935  The CLI format is:
936  l2fib flush-mac interface <if-name>
937 */
938 static clib_error_t *
940  unformat_input_t * input, vlib_cli_command_t * cmd)
941 {
942  vnet_main_t *vnm = vnet_get_main ();
943  clib_error_t *error = 0;
945 
947  {
948  error = clib_error_return (0, "unknown interface `%U'",
949  format_unformat_error, input);
950  goto done;
951  }
952 
954 
955 done:
956  return error;
957 }
958 
959 /**
960  Flush all MACs, except static ones
961  The CLI format is:
962  l2fib flush-mac all
963 */
964 static clib_error_t *
966  unformat_input_t * input, vlib_cli_command_t * cmd)
967 {
969  return 0;
970 }
971 
972 /*?
973  * This command kick off ager to delete all existing MAC Address entries,
974  * except static ones, associated with an interface from the L2 FIB table.
975  *
976  * @cliexpar
977  * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
978  * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
979 ?*/
980 /* *INDENT-OFF* */
982  .path = "l2fib flush-mac all",
983  .short_help = "l2fib flush-mac all",
984  .function = l2fib_flush_mac_all,
985 };
986 /* *INDENT-ON* */
987 
988 /*?
989  * This command kick off ager to delete all existing MAC Address entries,
990  * except static ones, associated with an interface from the L2 FIB table.
991  *
992  * @cliexpar
993  * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
994  * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
995 ?*/
996 /* *INDENT-OFF* */
998  .path = "l2fib flush-mac interface",
999  .short_help = "l2fib flush-mac interface <if-name>",
1000  .function = l2fib_flush_mac_int,
1001 };
1002 /* *INDENT-ON* */
1003 
1004 /**
1005  Flush bridge-domain MACs except static ones.
1006  The CLI format is:
1007  l2fib flush-mac bridge-domain <bd-id>
1008 */
1009 static clib_error_t *
1011  unformat_input_t * input, vlib_cli_command_t * cmd)
1012 {
1013  bd_main_t *bdm = &bd_main;
1014  clib_error_t *error = 0;
1015  u32 bd_index, bd_id;
1016  uword *p;
1017 
1018  if (!unformat (input, "%d", &bd_id))
1019  {
1020  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
1021  format_unformat_error, input);
1022  goto done;
1023  }
1024 
1025  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1026  if (p)
1027  bd_index = *p;
1028  else
1029  return clib_error_return (0, "No such bridge domain %d", bd_id);
1030 
1031  l2fib_flush_bd_mac (vm, bd_index);
1032 
1033 done:
1034  return error;
1035 }
1036 
1037 /*?
1038  * This command kick off ager to delete all existing MAC Address entries,
1039  * except static ones, in a bridge domain from the L2 FIB table.
1040  *
1041  * @cliexpar
1042  * Example of how to flush MAC Address entries learned in a bridge domain from the L2 FIB table:
1043  * @cliexcmd{l2fib flush-mac bridge-domain 1000}
1044 ?*/
1045 /* *INDENT-OFF* */
1047  .path = "l2fib flush-mac bridge-domain",
1048  .short_help = "l2fib flush-mac bridge-domain <bd-id>",
1049  .function = l2fib_flush_mac_bd,
1050 };
1051 /* *INDENT-ON* */
1052 
1053 clib_error_t *
1055 {
1057  if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0 &&
1058  l2_input_is_bridge (config))
1060  return 0;
1061 }
1062 
1064 
1065 BVT (clib_bihash) * get_mac_table (void)
1066 {
1067  l2fib_main_t *mp = &l2fib_main;
1068  return &mp->mac_table;
1069 }
1070 
1071 static_always_inline void *
1072 allocate_mac_evt_buf (u32 client, u32 client_index)
1073 {
1076  (sizeof (*mp) + (fm->max_macs_in_event * sizeof (vl_api_mac_entry_t)));
1077  mp->_vl_msg_id = htons (l2input_main.msg_id_base + VL_API_L2_MACS_EVENT);
1078  mp->pid = htonl (client);
1079  mp->client_index = client_index;
1080  return mp;
1081 }
1082 
1084 l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
1085 {
1088 
1089  BVT (clib_bihash) * h = &fm->mac_table;
1090  int i, j, k;
1091  f64 last_start = start_time;
1092  f64 accum_t = 0;
1093  f64 delta_t = 0;
1094  u32 evt_idx = 0;
1095  u32 learn_count = 0;
1096  u32 client = lm->client_pid;
1097  u32 cl_idx = lm->client_index;
1098  vl_api_l2_macs_event_t *mp = 0;
1099  vl_api_registration_t *reg = 0;
1100  u32 bd_index;
1101  static u32 *bd_learn_counts = 0;
1102 
1103  /* Don't scan the l2 fib if it hasn't been instantiated yet */
1104  if (alloc_arena (h) == 0)
1105  return 0.0;
1106 
1107  vec_reset_length (bd_learn_counts);
1108  vec_validate (bd_learn_counts, vec_len (l2input_main.bd_configs) - 1);
1109 
1110  if (client)
1111  {
1112  mp = allocate_mac_evt_buf (client, cl_idx);
1114  }
1115 
1116  for (i = 0; i < h->nbuckets; i++)
1117  {
1118  /* allow no more than 20us without a pause */
1119  delta_t = vlib_time_now (vm) - last_start;
1120  if (delta_t > 20e-6)
1121  {
1122  vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
1123  /* in case a new bd was created while sleeping */
1124  vec_validate (bd_learn_counts,
1126  last_start = vlib_time_now (vm);
1127  accum_t += delta_t;
1128  }
1129 
1130  if (i < (h->nbuckets - 3))
1131  {
1132  BVT (clib_bihash_bucket) * b =
1133  BV (clib_bihash_get_bucket) (h, i + 3);
1135  b = BV (clib_bihash_get_bucket) (h, i + 1);
1136  if (!BV (clib_bihash_bucket_is_empty) (b))
1137  {
1138  BVT (clib_bihash_value) * v =
1139  BV (clib_bihash_get_value) (h, b->offset);
1140  clib_prefetch_load (v);
1141  }
1142  }
1143 
1144  BVT (clib_bihash_bucket) * b = BV (clib_bihash_get_bucket) (h, i);
1145  if (BV (clib_bihash_bucket_is_empty) (b))
1146  continue;
1147  BVT (clib_bihash_value) * v = BV (clib_bihash_get_value) (h, b->offset);
1148  for (j = 0; j < (1 << b->log2_pages); j++)
1149  {
1150  for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
1151  {
1152  if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL)
1153  continue;
1154 
1155  l2fib_entry_key_t key = {.raw = v->kvp[k].key };
1156  l2fib_entry_result_t result = {.raw = v->kvp[k].value };
1157 
1158  if (!l2fib_entry_result_is_set_AGE_NOT (&result))
1159  {
1160  learn_count++;
1161  vec_elt (bd_learn_counts, key.fields.bd_index)++;
1162  }
1163 
1164  if (client)
1165  {
1166  if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event))
1167  {
1168  /* event message full, send it and start a new one */
1169  if (reg && vl_api_can_send_msg (reg))
1170  {
1171  mp->n_macs = htonl (evt_idx);
1172  vl_api_send_msg (reg, (u8 *) mp);
1173  mp = allocate_mac_evt_buf (client, cl_idx);
1174  }
1175  else
1176  {
1177  if (reg)
1178  clib_warning ("MAC event to pid %d queue stuffed!"
1179  " %d MAC entries lost", client,
1180  evt_idx);
1181  }
1182  evt_idx = 0;
1183  }
1184 
1185  if (l2fib_entry_result_is_set_LRN_EVT (&result))
1186  {
1187  /* copy mac entry to event msg */
1188  clib_memcpy_fast (mp->mac[evt_idx].mac_addr,
1189  key.fields.mac, 6);
1190  mp->mac[evt_idx].action =
1191  l2fib_entry_result_is_set_LRN_MOV (&result) ?
1192  (vl_api_mac_event_action_t) MAC_EVENT_ACTION_MOVE
1193  : (vl_api_mac_event_action_t) MAC_EVENT_ACTION_ADD;
1194  mp->mac[evt_idx].action =
1195  htonl (mp->mac[evt_idx].action);
1196  mp->mac[evt_idx].sw_if_index =
1197  htonl (result.fields.sw_if_index);
1198  /* clear event bits and update mac entry */
1199  l2fib_entry_result_clear_LRN_EVT (&result);
1200  l2fib_entry_result_clear_LRN_MOV (&result);
1201  BVT (clib_bihash_kv) kv;
1202  kv.key = key.raw;
1203  kv.value = result.raw;
1204  BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1);
1205  evt_idx++;
1206  continue; /* skip aging */
1207  }
1208  }
1209 
1210  if (event_only || l2fib_entry_result_is_set_AGE_NOT (&result))
1211  continue; /* skip aging - static_mac always age_not */
1212 
1213  /* start aging processing */
1214  u32 bd_index = key.fields.bd_index;
1215  u32 sw_if_index = result.fields.sw_if_index;
1216  u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index);
1217  if (result.fields.sn != sn)
1218  goto age_out; /* stale mac */
1219 
1220  l2_bridge_domain_t *bd_config =
1222 
1223  if (bd_config->mac_age == 0)
1224  continue; /* skip aging */
1225 
1226  i16 delta = (u8) (start_time / 60) - result.fields.timestamp;
1227  delta += delta < 0 ? 256 : 0;
1228 
1229  if (delta < bd_config->mac_age)
1230  continue; /* still valid */
1231 
1232  age_out:
1233  if (client)
1234  {
1235  /* copy mac entry to event msg */
1236  clib_memcpy_fast (mp->mac[evt_idx].mac_addr, key.fields.mac,
1237  6);
1238  mp->mac[evt_idx].action =
1239  (vl_api_mac_event_action_t) MAC_EVENT_ACTION_DELETE;
1240  mp->mac[evt_idx].action = htonl (mp->mac[evt_idx].action);
1241  mp->mac[evt_idx].sw_if_index =
1242  htonl (result.fields.sw_if_index);
1243  evt_idx++;
1244  }
1245  /* delete mac entry */
1246  BVT (clib_bihash_kv) kv;
1247  kv.key = key.raw;
1248  BV (clib_bihash_add_del) (&fm->mac_table, &kv, 0);
1249  learn_count--;
1250  vec_elt (bd_learn_counts, key.fields.bd_index)--;
1251  /*
1252  * Note: we may have just freed the bucket's backing
1253  * storage, so check right here...
1254  */
1255  if (BV (clib_bihash_bucket_is_empty) (b))
1256  goto doublebreak;
1257  }
1258  v++;
1259  }
1260  doublebreak:
1261  ;
1262  }
1263 
1264  /* keep learn count consistent */
1265  l2learn_main.global_learn_count = learn_count;
1267  {
1268  vec_elt (l2input_main.bd_configs, bd_index).learn_count =
1269  vec_elt (bd_learn_counts, bd_index);
1270  }
1271 
1272  if (mp)
1273  {
1274  /* send any outstanding mac event message else free message buffer */
1275  if (evt_idx)
1276  {
1277  if (reg && vl_api_can_send_msg (reg))
1278  {
1279  mp->n_macs = htonl (evt_idx);
1280  vl_api_send_msg (reg, (u8 *) mp);
1281  }
1282  else
1283  {
1284  if (reg)
1285  clib_warning ("MAC event to pid %d queue stuffed!"
1286  " %d MAC entries lost", client, evt_idx);
1287  vl_msg_api_free (mp);
1288  }
1289  }
1290  else
1291  vl_msg_api_free (mp);
1292  }
1293  return delta_t + accum_t;
1294 }
1295 
1296 static uword
1298  vlib_frame_t * f)
1299 {
1300  uword event_type, *event_data = 0;
1303  bool enabled = 0;
1304  f64 start_time, next_age_scan_time = CLIB_TIME_MAX;
1305 
1306  while (1)
1307  {
1308  if (lm->client_pid)
1309  vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay);
1310  else if (enabled)
1311  {
1312  f64 t = next_age_scan_time - vlib_time_now (vm);
1314  }
1315  else
1317 
1318  event_type = vlib_process_get_events (vm, &event_data);
1319  vec_reset_length (event_data);
1320 
1321  start_time = vlib_time_now (vm);
1322  enum
1323  { SCAN_MAC_AGE, SCAN_MAC_EVENT, SCAN_DISABLE } scan = SCAN_MAC_AGE;
1324 
1325  switch (event_type)
1326  {
1327  case ~0: /* timer expired */
1328  if (lm->client_pid != 0 && start_time < next_age_scan_time)
1329  scan = SCAN_MAC_EVENT;
1330  break;
1331 
1333  enabled = 1;
1334  break;
1335 
1337  enabled = 0;
1338  scan = SCAN_DISABLE;
1339  break;
1340 
1342  break;
1343 
1344  default:
1345  ASSERT (0);
1346  }
1347 
1348  if (scan == SCAN_MAC_EVENT)
1349  l2fib_main.evt_scan_duration = l2fib_scan (vm, start_time, 1);
1350  else
1351  {
1352  if (scan == SCAN_MAC_AGE)
1353  l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0);
1354  if (scan == SCAN_DISABLE)
1355  {
1358  }
1359  /* schedule next scan */
1360  if (enabled)
1361  next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL;
1362  else
1363  next_age_scan_time = CLIB_TIME_MAX;
1364  }
1365  }
1366  return 0;
1367 }
1368 
1369 /* *INDENT-OFF* */
1371  .function = l2fib_mac_age_scanner_process,
1372  .type = VLIB_NODE_TYPE_PROCESS,
1373  .name = "l2fib-mac-age-scanner-process",
1374 };
1375 /* *INDENT-ON* */
1376 
1377 clib_error_t *
1379 {
1380  l2fib_main_t *mp = &l2fib_main;
1382  u8 test_mac[6];
1383 
1384  mp->vlib_main = vm;
1385  mp->vnet_main = vnet_get_main ();
1386  if (mp->mac_table_n_buckets == 0)
1388  if (mp->mac_table_memory_size == 0)
1390  mp->mac_table_initialized = 0;
1391 
1392  /* verify the key constructor is good, since it is endian-sensitive */
1393  clib_memset (test_mac, 0, sizeof (test_mac));
1394  test_mac[0] = 0x11;
1395  test_key.raw = 0;
1396  test_key.raw = l2fib_make_key ((u8 *) & test_mac, 0x1234);
1397  ASSERT (test_key.fields.mac[0] == 0x11);
1398  ASSERT (test_key.fields.bd_index == 0x1234);
1399 
1400  return 0;
1401 }
1402 
1404 
1405 static clib_error_t *
1407 {
1408  l2fib_main_t *lm = &l2fib_main;
1409  uword table_size = ~0;
1410  u32 n_buckets = ~0;
1411 
1412  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1413  {
1414  if (unformat (input, "table-size %U", unformat_memory_size,
1415  &table_size))
1416  ;
1417  else if (unformat (input, "num-buckets %u", &n_buckets))
1418  ;
1419  else
1420  return clib_error_return (0, "unknown input `%U'",
1421  format_unformat_error, input);
1422  }
1423 
1424  if (n_buckets != ~0)
1425  {
1426  if (!is_pow2 (n_buckets))
1427  return clib_error_return (0, "num-buckets must be power of 2");
1428  lm->mac_table_n_buckets = n_buckets;
1429  }
1430 
1431  if (table_size != ~0)
1432  lm->mac_table_memory_size = table_size;
1433  return 0;
1434 }
1435 
1437 
1438 /*
1439  * fd.io coding-style-patch-verification: ON
1440  *
1441  * Local Variables:
1442  * eval: (c-set-style "gnu")
1443  * End:
1444  */
vec_reset_length
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
Definition: vec_bootstrap.h:194
l2fib_add_filter_entry
static void l2fib_add_filter_entry(const u8 *mac, u32 bd_index)
Definition: l2_fib.h:453
vlib.h
l2fib_flush_int_mac
void l2fib_flush_int_mac(vlib_main_t *vm, u32 sw_if_index)
Flush all non static MACs from an interface.
Definition: l2_fib.c:901
vl_api_l2_macs_event_t
L2 MAC event for a list of learned or aged MACs.
Definition: l2.api:221
tmp
u32 * tmp
Definition: interface_output.c:1096
vl_api_client_index_to_registration
static vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
Definition: api.h:79
unformat_ethernet_address
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:233
l2fib_show_walk_cb
static int l2fib_show_walk_cb(BVT(clib_bihash_kv) *kvp, void *arg)
Definition: l2_fib.c:179
api.h
l2fib_set_scan_delay_cli
static vlib_cli_command_t l2fib_set_scan_delay_cli
(constructor) VLIB_CLI_COMMAND (l2fib_set_scan_delay_cli)
Definition: l2_fib.c:868
l2_bridge_domain_t
Definition: l2_bd.h:63
mac
vl_api_mac_address_t mac
Definition: l2.api:559
unformat_user
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
allocate_mac_evt_buf
static_always_inline void * allocate_mac_evt_buf(u32 client, u32 client_index)
Definition: l2_fib.c:1072
bihash_template.c
l2fib_main_t::age_scan_duration
f64 age_scan_duration
Definition: l2_fib.h:59
L2_MAC_AGE_PROCESS_EVENT_START
@ L2_MAC_AGE_PROCESS_EVENT_START
Definition: l2_learn.h:61
raw
const char *const const char *const raw
Definition: cJSON.h:270
vnet_sw_interface_t
Definition: interface.h:869
l2_input_config_t
Definition: l2_input.h:42
l2input_main
l2input_main_t l2input_main
Definition: l2_input_node.c:78
l2fib_test_command
static vlib_cli_command_t l2fib_test_command
(constructor) VLIB_CLI_COMMAND (l2fib_test_command)
Definition: l2_fib.c:728
format_l2fib_entry_result_flags
u8 * format_l2fib_entry_result_flags(u8 *s, va_list *args)
Definition: l2_fib.c:53
l2input_bd_config
static_always_inline l2_bridge_domain_t * l2input_bd_config(u32 bd_index)
Definition: l2_input.h:116
l2fib_dump_walk_ctx_t_
Definition: l2_fib.c:102
vl_api_send_msg
static void vl_api_send_msg(vl_api_registration_t *rp, u8 *elem)
Definition: api.h:35
BIHASH_KVP_PER_PAGE
#define BIHASH_KVP_PER_PAGE
Definition: bihash_16_8.h:25
l2fib_entry_result_t_::fields
struct l2fib_entry_result_t_::@469::@471 fields
vlib_process_wait_for_event
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:660
f
vlib_frame_t * f
Definition: interface_output.c:1098
vnet_get_sw_interface_or_null
static vnet_sw_interface_t * vnet_get_sw_interface_or_null(vnet_main_t *vnm, u32 sw_if_index)
Definition: interface_funcs.h:64
L2FIB_AGE_SCAN_INTERVAL
#define L2FIB_AGE_SCAN_INTERVAL
Definition: l2_fib.h:31
L2_MAC_AGE_PROCESS_EVENT_STOP
@ L2_MAC_AGE_PROCESS_EVENT_STOP
Definition: l2_learn.h:62
format_ethernet_address
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
l2input_intf_config
l2_input_config_t * l2input_intf_config(u32 sw_if_index)
Get a pointer to the config for the given interface.
Definition: l2_input.c:167
bd_main_t
Definition: l2_bd.h:33
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
u8
#define u8
Padding.
Definition: clib.h:121
vlib_cli_command_t::path
char * path
Definition: cli.h:96
u16
unsigned short u16
Definition: types.h:57
l2learn_main_t::global_learn_count
u32 global_learn_count
Definition: l2_learn.h:33
VNET_SW_INTERFACE_FLAG_ADMIN_UP
@ VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:844
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
l2learn_main_t::client_index
u32 client_index
Definition: l2_learn.h:43
fm
vnet_feature_main_t * fm
Definition: nat44_ei_hairpinning.c:592
l2fib_show_walk_ctx_t
struct l2fib_show_walk_ctx_t_ l2fib_show_walk_ctx_t
l2fib_show_walk_ctx_t_::add
u8 add
Definition: l2_fib.c:174
L2FIB_MEMORY_SIZE
#define L2FIB_MEMORY_SIZE
Definition: l2_fib.h:28
l2_learn.h
l2fib_start_ager_scan
void l2fib_start_ager_scan(vlib_main_t *vm)
Kick off ager to scan MACs to age/delete MAC entries.
Definition: l2_fib.c:878
unformat_input_t
struct _unformat_input_t unformat_input_t
clear_l2fib_cli
static vlib_cli_command_t clear_l2fib_cli
(constructor) VLIB_CLI_COMMAND (clear_l2fib_cli)
Definition: l2_fib.c:420
clib_bihash_get_value
static void * clib_bihash_get_value(clib_bihash *h, uword offset)
Get pointer to value page given its clib mheap offset.
vlib_frame_t
Definition: node.h:372
l2_bridge_domain_t::mac_age
u8 mac_age
Definition: l2_bd.h:105
vlib_process_signal_event
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:1019
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
l2fib_del
static clib_error_t * l2fib_del(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Delete an entry from the L2FIB.
Definition: l2_fib.c:785
ethernet.h
h
h
Definition: flowhash_template.h:372
error
Definition: cJSON.c:88
l2fib_add_entry
void l2fib_add_entry(const u8 *mac, u32 bd_index, u32 sw_if_index, l2fib_entry_result_flags_t flags)
Add an entry to the l2fib.
Definition: l2_fib.c:441
vl_api_l2_macs_event_t::client_index
u32 client_index
Definition: l2.api:223
l2_fib.h
key
typedef key
Definition: ipsec_types.api:91
lfib_config
static clib_error_t * lfib_config(vlib_main_t *vm, unformat_input_t *input)
Definition: l2_fib.c:1406
l2fib_init
clib_error_t * l2fib_init(vlib_main_t *vm)
Definition: l2_fib.c:1378
VLIB_CONFIG_FUNCTION
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:181
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
vec_elt
#define vec_elt(v, i)
Get vector value at index i.
Definition: vec_bootstrap.h:210
l2fib_dump_walk_ctx_t
struct l2fib_dump_walk_ctx_t_ l2fib_dump_walk_ctx_t
l2_bridge_domain_t::learn_count
u32 learn_count
Definition: l2_bd.h:117
i16
signed short i16
Definition: types.h:46
vlib_process_get_events
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type,...
Definition: node_funcs.h:583
show_l2fib_cli
static vlib_cli_command_t show_l2fib_cli
(constructor) VLIB_CLI_COMMAND (show_l2fib_cli)
Definition: l2_fib.c:357
hash.h
count
u8 count
Definition: dhcp.api:208
l2learn_main_t
Definition: l2_learn.h:26
unformat_memory_size
unformat_function_t unformat_memory_size
Definition: format.h:288
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
error.h
clear_l2fib
static clib_error_t * clear_l2fib(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Clear all entries in L2FIB.
Definition: l2_fib.c:401
clib_bihash_init
void clib_bihash_init(clib_bihash *h, char *name, u32 nbuckets, uword memory_size)
initialize a bounded index extensible hash table
bd_id
u32 bd_id
Definition: gbp.api:188
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
l2fib_flush_mac_all
static clib_error_t * l2fib_flush_mac_all(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Flush all MACs, except static ones The CLI format is: l2fib flush-mac all.
Definition: l2_fib.c:965
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
vnet_get_main
vnet_main_t * vnet_get_main(void)
Definition: pnat_test_stubs.h:56
incr_mac_address
static void incr_mac_address(u8 *mac)
Definition: l2_fib.c:74
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
vl_api_registration_
An API client registration, only in vpp/vlib.
Definition: api_common.h:47
hash_get
#define hash_get(h, key)
Definition: hash.h:249
l2fib_dump_walk_ctx_t_::l2fe_res
l2fib_entry_result_t * l2fe_res
Definition: l2_fib.c:106
unformat_check_input
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
l2fib_dump_walk_ctx_t_::l2fe_key
l2fib_entry_key_t * l2fe_key
Definition: l2_fib.c:105
l2fib_show_walk_ctx_t_::bd_index
u32 bd_index
Definition: l2_fib.c:172
l2fib_dump_walk_cb
static int l2fib_dump_walk_cb(BVT(clib_bihash_kv) *kvp, void *arg)
Definition: l2_fib.c:110
vlib_config_function_runtime_t
Definition: init.h:68
l2fib_main_t::evt_scan_duration
f64 evt_scan_duration
Definition: l2_fib.h:58
l2fib_flush_all_mac
void l2fib_flush_all_mac(vlib_main_t *vm)
Flush all non static MACs - flushes all valid BDs.
Definition: l2_fib.c:922
l2fib_show_walk_ctx_t_::first_entry
u8 first_entry
Definition: l2_fib.c:167
static_always_inline
#define static_always_inline
Definition: clib.h:112
L2FIB_NUM_BUCKETS
#define L2FIB_NUM_BUCKETS
Definition: l2_fib.h:27
vec_foreach_index
#define vec_foreach_index(var, v)
Iterate over vector indices.
Definition: vec_bootstrap.h:220
l2fib_clear_table
void l2fib_clear_table(void)
Definition: l2_fib.c:379
uword
u64 uword
Definition: types.h:112
if
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
clib_bihash_free
void clib_bihash_free(clib_bihash *h)
Destroy a bounded index extensible hash table.
BVT
BVT(clib_bihash)
The table of adjacencies indexed by the rewrite string.
Definition: l2_fib.c:1065
l2fib_sw_interface_up_down
clib_error_t * l2fib_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: l2_fib.c:1054
vl_api_l2_macs_event_t::n_macs
u32 n_macs
Definition: l2.api:225
l2fib_main_t::vlib_main
vlib_main_t * vlib_main
Definition: l2_fib.h:68
l2fib_set_scan_delay
static clib_error_t * l2fib_set_scan_delay(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l2_fib.c:845
l2fib_flush_mac_all_cli
static vlib_cli_command_t l2fib_flush_mac_all_cli
(constructor) VLIB_CLI_COMMAND (l2fib_flush_mac_all_cli)
Definition: l2_fib.c:981
l2fib_main_t::vnet_main
vnet_main_t * vnet_main
Definition: l2_fib.h:69
f64
double f64
Definition: types.h:142
format_unformat_error
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
l2fib_entry_result_t_
Definition: l2_fib.h:160
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
vnet_main_t::vlib_main
vlib_main_t * vlib_main
Definition: vnet.h:111
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
MAC_EVENT_ACTION_DELETE
@ MAC_EVENT_ACTION_DELETE
Definition: l2_fib.h:217
l2_input_is_bridge
static bool l2_input_is_bridge(const l2_input_config_t *input)
Definition: l2_input.h:236
l2fib_show_walk_ctx_t_::learn
u8 learn
Definition: l2_fib.c:173
l2_input_seq_num
static_always_inline u8 l2_input_seq_num(u32 sw_if_index)
Definition: l2_input.h:254
l2fib_main_t::mac_table_memory_size
uword mac_table_memory_size
Definition: l2_fib.h:52
l2fib_mac_age_scanner_process
static uword l2fib_mac_age_scanner_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: l2_fib.c:1297
l2fib_show_walk_ctx_t_::verbose
u8 verbose
Definition: l2_fib.c:168
l2learn_main_t::global_learn_limit
u32 global_learn_limit
Definition: l2_learn.h:36
vlib_node_registration_t
struct _vlib_node_registration vlib_node_registration_t
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
l2_bridge_domain_t::seq_num
u8 seq_num
Definition: l2_bd.h:108
l2fib_show_walk_ctx_t_::now
u8 now
Definition: l2_fib.c:175
l2_input.h
show_l2fib
static clib_error_t * show_l2fib(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Display the contents of the l2fib.
Definition: l2_fib.c:244
l2fib_entry_result_t_::raw
u64 raw
Definition: l2_fib.h:172
l2learn_main
l2learn_main_t l2learn_main
Definition: l2_learn.c:32
l2fib_flush_bd_mac
void l2fib_flush_bd_mac(vlib_main_t *vm, u32 bd_index)
Flush all non static MACs in a bridge domain.
Definition: l2_fib.c:911
l2fib_flush_mac_int_cli
static vlib_cli_command_t l2fib_flush_mac_int_cli
(constructor) VLIB_CLI_COMMAND (l2fib_flush_mac_int_cli)
Definition: l2_fib.c:997
vnet_main_t
Definition: vnet.h:76
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
l2fib_flush_mac_bd_cli
static vlib_cli_command_t l2fib_flush_mac_bd_cli
(constructor) VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli)
Definition: l2_fib.c:1046
l2fib_main_t
Definition: l2_fib.h:42
l2_input_seq_num_inc
void l2_input_seq_num_inc(u32 sw_if_index)
Definition: l2_input.c:238
clib_bihash_value
template key/value backing page structure
Definition: bihash_doc.h:44
vl_api_l2_macs_event_t::pid
u32 pid
Definition: l2.api:224
bd_is_valid
static u32 bd_is_valid(l2_bridge_domain_t *bd_config)
Definition: l2_bd.h:140
l2_bridge_domain_t::bd_id
u32 bd_id
Definition: l2_bd.h:83
foreach_l2fib_entry_result_attr
@ foreach_l2fib_entry_result_attr
Definition: l2_fib.h:149
l2fib_show_walk_ctx_t_
Definition: l2_fib.c:165
l2fib_make_key
static u64 l2fib_make_key(const u8 *mac_address, u16 bd_index)
Definition: l2_fib.h:241
vl_msg_api_free
void vl_msg_api_free(void *)
Definition: memory_shared.c:311
l2fib_scan
static_always_inline f64 l2fib_scan(vlib_main_t *vm, f64 start_time, u8 event_only)
Definition: l2_fib.c:1084
u64
unsigned long u64
Definition: types.h:89
unformat_vnet_sw_interface
unformat_function_t unformat_vnet_sw_interface
Definition: interface_funcs.h:462
vlib_process_wait_for_event_or_clock
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:755
format
description fragment has unexpected format
Definition: map.api:433
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
vl_api_can_send_msg
static int vl_api_can_send_msg(vl_api_registration_t *rp)
Definition: api.h:48
l2fib_main
l2fib_main_t l2fib_main
Definition: l2_fib.c:50
l2fib_cur_seq_num
static l2fib_seq_num_t l2fib_cur_seq_num(u32 bd_index, u32 sw_if_index)
Definition: l2_fib.c:428
vlib_process_suspend
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:486
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
l2_fib_mk_seq_num
static_always_inline l2fib_seq_num_t l2_fib_mk_seq_num(u8 bd_sn, u8 if_sn)
Definition: l2_fib.h:110
clib_prefetch_load
static_always_inline void clib_prefetch_load(void *p)
Definition: cache.h:92
l2fib_del_entry
u32 l2fib_del_entry(const u8 *mac, u32 bd_index, u32 sw_if_index)
Delete an entry from the l2fib.
Definition: l2_fib.c:742
ctx
long ctx[MAX_CONNS]
Definition: main.c:144
cli.h
l2fib_main_t::mac_table_initialized
u8 mac_table_initialized
Definition: l2_fib.h:55
vec_foreach
#define vec_foreach(var, vec)
Vector iterator.
Definition: vec_bootstrap.h:213
VLIB_NODE_TYPE_PROCESS
@ VLIB_NODE_TYPE_PROCESS
Definition: node.h:84
clib_bihash_add_del
int clib_bihash_add_del(clib_bihash *h, clib_bihash_kv *add_v, int is_add)
Add or delete a (key,value) pair from a bi-hash table.
l2fib_flush_mac_int
static clib_error_t * l2fib_flush_mac_int(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Flush MACs, except static ones, associated with an interface The CLI format is: l2fib flush-mac inter...
Definition: l2_fib.c:939
format_l2_fib_seq_num
u8 * format_l2_fib_seq_num(u8 *s, va_list *a)
Definition: l2_fib.c:153
l2input_main_t::msg_id_base
u16 msg_id_base
Definition: l2_input.h:99
vl_api_l2_macs_event_t::mac
vl_api_mac_entry_t mac[n_macs]
Definition: l2.api:226
l2fib_main_t::event_scan_delay
f64 event_scan_delay
Definition: l2_fib.h:62
l2fib_mac_age_scanner_process_node
vlib_node_registration_t l2fib_mac_age_scanner_process_node
(constructor) VLIB_REGISTER_NODE (l2fib_mac_age_scanner_process_node)
Definition: l2_fib.c:1370
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
bd_main
bd_main_t bd_main
Definition: l2_bd.c:44
l2fib_main_t::mac_table_n_buckets
uword mac_table_n_buckets
Definition: l2_fib.h:49
clib_bihash_foreach_key_value_pair
void clib_bihash_foreach_key_value_pair(clib_bihash *h, clib_bihash_foreach_key_value_pair_cb *callback, void *arg)
Visit active (key,value) pairs in a bi-hash table.
vlib_get_main
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
b
vlib_buffer_t ** b
Definition: nat44_ei_out2in.c:717
l2fib_dump_walk_ctx_t_::bd_index
u32 bd_index
Definition: l2_fib.c:104
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
a
a
Definition: bitmap.h:525
rt
vnet_interface_output_runtime_t * rt
Definition: interface_output.c:419
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
l2fib_del_cli
static vlib_cli_command_t l2fib_del_cli
(constructor) VLIB_CLI_COMMAND (l2fib_del_cli)
Definition: l2_fib.c:837
l2fib_add_cli
static vlib_cli_command_t l2fib_add_cli
(constructor) VLIB_CLI_COMMAND (l2fib_add_cli)
Definition: l2_fib.c:597
l2fib_flush_mac_bd
static clib_error_t * l2fib_flush_mac_bd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Flush bridge-domain MACs except static ones.
Definition: l2_fib.c:1010
l2fib_entry_result_flags_t
enum l2fib_entry_result_flags_t_ l2fib_entry_result_flags_t
i
int i
Definition: flowhash_template.h:376
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
MAC_EVENT_ACTION_MOVE
@ MAC_EVENT_ACTION_MOVE
Definition: l2_fib.h:218
l2fib_seq_num_t
u16 l2fib_seq_num_t
A combined representation of the sequence number associated with the interface and the BD.
Definition: l2_fib.h:107
l2fib_entry_key_t
Definition: l2_fib.h:77
test_key
static unsigned char test_key[46]
Definition: vcl_test_protos.c:680
vlib_time_now
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:327
L2_MAC_AGE_PROCESS_EVENT_ONE_PASS
@ L2_MAC_AGE_PROCESS_EVENT_ONE_PASS
Definition: l2_learn.h:63
vnet.h
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(l2fib_sw_interface_up_down)
vlib_node_runtime_t
Definition: node.h:454
format_vnet_sw_if_index_name_with_NA
u8 * format_vnet_sw_if_index_name_with_NA(u8 *s, va_list *args)
Format sw_if_index.
Definition: l2_fib.c:86
l2input_main_t::configs
l2_input_config_t * configs
Definition: l2_input.h:90
l2fib_table_dump
void l2fib_table_dump(u32 bd_index, l2fib_entry_key_t **l2fe_key, l2fib_entry_result_t **l2fe_res)
Definition: l2_fib.c:129
vlib_cli_command_t
Definition: cli.h:92
L2FIB_ENTRY_RESULT_FLAG_NONE
@ L2FIB_ENTRY_RESULT_FLAG_NONE
Definition: l2_fib.h:147
is_pow2
static uword is_pow2(uword x)
Definition: clib.h:267
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
l2_fib_extract_seq_num
void l2_fib_extract_seq_num(l2fib_seq_num_t sn, u8 *bd_sn, u8 *if_sn)
Definition: l2_fib.c:146
l2_bd.h
MAC_EVENT_ACTION_ADD
@ MAC_EVENT_ACTION_ADD
Definition: l2_fib.h:216
bd_main_t::bd_index_by_bd_id
uword * bd_index_by_bd_id
Definition: l2_bd.h:36
l2fib_main_t::max_macs_in_event
u32 max_macs_in_event
Definition: l2_fib.h:65
CLIB_TIME_MAX
#define CLIB_TIME_MAX
Definition: time.h:227
l2fib_show_walk_ctx_t_::total_entries
u32 total_entries
Definition: l2_fib.c:171
l2fib_show_walk_ctx_t_::vm
vlib_main_t * vm
Definition: l2_fib.c:169
UNFORMAT_END_OF_INPUT
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
l2fib_table_init
void l2fib_table_init(void)
Definition: l2_fib.c:365
l2input_main_t::bd_configs
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:93
l2learn_main_t::client_pid
u32 client_pid
Definition: l2_learn.h:42
format_vnet_sw_interface_name
format_function_t format_vnet_sw_interface_name
Definition: interface_funcs.h:456
l2fib_add
static clib_error_t * l2fib_add(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Add an entry to the L2FIB.
Definition: l2_fib.c:501
l2fib_test_command_fn
static clib_error_t * l2fib_test_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l2_fib.c:606
vl_msg_api_alloc
void * vl_msg_api_alloc(int nbytes)
Definition: memory_shared.c:199
VLIB_REGISTER_NODE
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
swif
u32 swif
Definition: interface_output.c:1096
l2fib_show_walk_ctx_t_::vnm
vnet_main_t * vnm
Definition: l2_fib.c:170
flags
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105