FD.io VPP  v17.01.1-3-gc6833f8
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/pg/pg.h>
22 #include <vnet/ethernet/ethernet.h>
23 #include <vlib/cli.h>
24 
25 #include <vppinfra/error.h>
26 #include <vppinfra/hash.h>
27 #include <vnet/l2/l2_input.h>
28 #include <vnet/l2/l2_fib.h>
29 #include <vnet/l2/l2_learn.h>
30 #include <vnet/l2/l2_bd.h>
31 
33 
34 /**
35  * @file
36  * @brief Ethernet MAC Address FIB Table Management.
37  *
38  * The MAC Address forwarding table for bridge-domains is called the l2fib.
39  * Entries are added automatically as part of mac learning, but MAC Addresses
40  * entries can also be added manually.
41  *
42  */
43 
44 typedef struct
45 {
46 
47  /* hash table */
48  BVT (clib_bihash) mac_table;
49 
50  /* convenience variables */
53 } l2fib_main_t;
54 
56 
57 
58 /** Format sw_if_index. If the value is ~0, use the text "N/A" */
59 u8 *
61 {
62  vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
63  u32 sw_if_index = va_arg (*args, u32);
64  if (sw_if_index == ~0)
65  return format (s, "N/A");
66  else
67  return format (s, "%U",
69  vnet_get_sw_interface (vnm, sw_if_index));
70 }
71 
72 void
73 l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key,
74  l2fib_entry_result_t ** l2fe_res)
75 {
76  l2fib_main_t *msm = &l2fib_main;
77  BVT (clib_bihash) * h = &msm->mac_table;
81  l2fib_entry_result_t result;
82  int i, j, k;
83 
84  for (i = 0; i < h->nbuckets; i++)
85  {
86  b = &h->buckets[i];
87  if (b->offset == 0)
88  continue;
89  v = BV (clib_bihash_get_value) (h, b->offset);
90  for (j = 0; j < (1 << b->log2_pages); j++)
91  {
92  for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
93  {
94  if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL)
95  continue;
96 
97  key.raw = v->kvp[k].key;
98  result.raw = v->kvp[k].value;
99 
100  if ((bd_index == ~0) || (bd_index == key.fields.bd_index))
101  {
102  vec_add1 (*l2fe_key, key);
103  vec_add1 (*l2fe_res, result);
104  }
105  }
106  v++;
107  }
108  }
109 }
110 
111 /** Display the contents of the l2fib. */
112 static clib_error_t *
114  unformat_input_t * input, vlib_cli_command_t * cmd)
115 {
116  bd_main_t *bdm = &bd_main;
117  l2fib_main_t *msm = &l2fib_main;
118  l2_bridge_domain_t *bd_config;
119  BVT (clib_bihash) * h = &msm->mac_table;
121  BVT (clib_bihash_value) * v;
122  l2fib_entry_key_t key;
123  l2fib_entry_result_t result;
124  u32 first_entry = 1;
125  u64 total_entries = 0;
126  int i, j, k;
127  u8 verbose = 0;
128  u8 raw = 0;
129  u32 bd_id, bd_index = ~0;
130  u8 now = (u8) (vlib_time_now (vm) / 60);
131  u8 *s = 0;
132 
133  if (unformat (input, "raw"))
134  raw = 1;
135  else if (unformat (input, "verbose"))
136  verbose = 1;
137  else if (unformat (input, "bd_index %d", &bd_index))
138  verbose = 1;
139  else if (unformat (input, "bd_id %d", &bd_id))
140  {
141  uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
142  if (p)
143  {
144  verbose = 1;
145  bd_index = p[0];
146  }
147  else
148  {
149  vlib_cli_output (vm, "no such bridge domain id");
150  return 0;
151  }
152  }
153 
154  for (i = 0; i < h->nbuckets; i++)
155  {
156  b = &h->buckets[i];
157  if (b->offset == 0)
158  continue;
159  v = BV (clib_bihash_get_value) (h, b->offset);
160  for (j = 0; j < (1 << b->log2_pages); j++)
161  {
162  for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
163  {
164  if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL)
165  continue;
166 
167  if (verbose && first_entry)
168  {
169  first_entry = 0;
170  vlib_cli_output (vm,
171  "%=19s%=7s%=30s%=7s%=8s%=8s%=5s%=16s",
172  "Mac Address", "BD Idx", "Interface",
173  "Index", "static", "filter", "bvi",
174  "Mac Age (min)");
175  }
176 
177  key.raw = v->kvp[k].key;
178  result.raw = v->kvp[k].value;
179 
180  if (verbose
181  & ((bd_index >> 31) || (bd_index == key.fields.bd_index)))
182  {
184  key.fields.bd_index);
185 
186  if (bd_config->mac_age)
187  {
188  i16 delta = now - result.fields.timestamp;
189  delta += delta < 0 ? 256 : 0;
190  s = format (s, "%d", delta);
191  }
192  else
193  s = format (s, "disabled");
194 
195  vlib_cli_output (vm,
196  "%=19U%=7d%=30U%=7d%=8d%=8d%=5d%=16v",
198  key.fields.bd_index,
200  msm->vnet_main, result.fields.sw_if_index,
201  result.fields.sw_if_index == ~0
202  ? -1 : result.fields.sw_if_index,
203  result.fields.static_mac,
204  result.fields.filter,
205  result.fields.bvi, s);
206  vec_reset_length (s);
207  }
208  total_entries++;
209  }
210  v++;
211  }
212  }
213 
214  if (total_entries == 0)
215  vlib_cli_output (vm, "no l2fib entries");
216  else
217  vlib_cli_output (vm, "%lld l2fib entries", total_entries);
218 
219  if (raw)
220  vlib_cli_output (vm, "Raw Hash Table:\n%U\n",
221  BV (format_bihash), h, 1 /* verbose */ );
222 
223  vec_free (s);
224  return 0;
225 }
226 
227 /*?
228  * This command dispays the MAC Address entries of the L2 FIB table.
229  * Output can be filtered to just get the number of MAC Addresses or display
230  * each MAC Address for all bridge domains or just a single bridge domain.
231  *
232  * @cliexpar
233  * Example of how to display the number of MAC Address entries in the L2
234  * FIB table:
235  * @cliexstart{show l2fib}
236  * 3 l2fib entries
237  * @cliexend
238  * Example of how to display all the MAC Address entries in the L2
239  * FIB table:
240  * @cliexstart{show l2fib verbose}
241  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
242  * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
243  * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
244  * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
245  * 3 l2fib entries
246  * @cliexend
247 ?*/
248 /* *INDENT-OFF* */
249 VLIB_CLI_COMMAND (show_l2fib_cli, static) = {
250  .path = "show l2fib",
251  .short_help = "show l2fib [verbose | bd_id <nn> | bd_index <nn> | raw]",
252  .function = show_l2fib,
253 };
254 /* *INDENT-ON* */
255 
256 
257 /* Remove all entries from the l2fib */
258 void
259 l2fib_clear_table (uint keep_static)
260 {
261  l2fib_main_t *mp = &l2fib_main;
262 
263  if (keep_static)
264  {
265  /* TODO: remove only non-static entries */
266  }
267  else
268  {
269  /* Remove all entries */
270  BV (clib_bihash_free) (&mp->mac_table);
271  BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
273  }
274 
276 }
277 
278 /** Clear all entries in L2FIB.
279  * @TODO: Later we may want a way to remove only the non-static entries
280  */
281 static clib_error_t *
283  unformat_input_t * input, vlib_cli_command_t * cmd)
284 {
285  l2fib_clear_table (0);
286  return 0;
287 }
288 
289 /*?
290  * This command clears all the MAC Address entries from the L2 FIB table.
291  *
292  * @cliexpar
293  * Example of how to clear the L2 FIB Table:
294  * @cliexcmd{clear l2fib}
295  * Example to show the L2 FIB Table has been cleared:
296  * @cliexstart{show l2fib verbose}
297  * no l2fib entries
298  * @cliexend
299 ?*/
300 /* *INDENT-OFF* */
301 VLIB_CLI_COMMAND (clear_l2fib_cli, static) = {
302  .path = "clear l2fib",
303  .short_help = "clear l2fib",
304  .function = clear_l2fib,
305 };
306 /* *INDENT-ON* */
307 
308 
309 /**
310  * Add an entry to the l2fib.
311  * If the entry already exists then overwrite it
312  */
313 void
315  u32 bd_index,
316  u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac)
317 {
318  l2fib_entry_key_t key;
319  l2fib_entry_result_t result;
320  __attribute__ ((unused)) u32 bucket_contents;
321  l2fib_main_t *mp = &l2fib_main;
322  BVT (clib_bihash_kv) kv;
323 
324  /* set up key */
325  key.raw = l2fib_make_key ((u8 *) & mac, bd_index);
326 
327  /* set up result */
328  result.raw = 0; /* clear all fields */
329  result.fields.sw_if_index = sw_if_index;
330  result.fields.static_mac = static_mac;
331  result.fields.filter = filter_mac;
332  result.fields.bvi = bvi_mac;
333 
334  kv.key = key.raw;
335  kv.value = result.raw;
336 
337  BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ );
338 
339  /* increment counter if dynamically learned mac */
340  if (result.fields.static_mac)
341  {
343  }
344 }
345 
346 /**
347  * Add an entry to the L2FIB.
348  * The CLI format is:
349  * l2fib add <mac> <bd> <intf> [static] [bvi]
350  * l2fib add <mac> <bd> filter
351  * Note that filter and bvi entries are always static
352  */
353 static clib_error_t *
355  unformat_input_t * input, vlib_cli_command_t * cmd)
356 {
357  bd_main_t *bdm = &bd_main;
358  vnet_main_t *vnm = vnet_get_main ();
359  clib_error_t *error = 0;
360  u64 mac;
361  u32 bd_id;
362  u32 bd_index;
363  u32 sw_if_index = ~0;
364  u32 filter_mac = 0;
365  u32 static_mac = 0;
366  u32 bvi_mac = 0;
367  uword *p;
368 
369  if (!unformat_user (input, unformat_ethernet_address, &mac))
370  {
371  error = clib_error_return (0, "expected mac address `%U'",
372  format_unformat_error, input);
373  goto done;
374  }
375 
376  if (!unformat (input, "%d", &bd_id))
377  {
378  error = clib_error_return (0, "expected bridge domain ID `%U'",
379  format_unformat_error, input);
380  goto done;
381  }
382 
383  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
384  if (!p)
385  {
386  error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
387  goto done;
388  }
389  bd_index = p[0];
390 
391  if (unformat (input, "filter"))
392  {
393  filter_mac = 1;
394  static_mac = 1;
395 
396  }
397  else
398  {
399 
400  if (!unformat_user
401  (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
402  {
403  error = clib_error_return (0, "unknown interface `%U'",
404  format_unformat_error, input);
405  goto done;
406  }
407  if (unformat (input, "static"))
408  {
409  static_mac = 1;
410  }
411  else if (unformat (input, "bvi"))
412  {
413  bvi_mac = 1;
414  static_mac = 1;
415  }
416  }
417 
418  l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac,
419  bvi_mac);
420 
421 done:
422  return error;
423 }
424 
425 /*?
426  * This command adds a MAC Address entry to the L2 FIB table
427  * of an existing bridge-domain. The MAC Address can be static
428  * or dynamic. This command also allows a filter to be added,
429  * such that packets with given MAC Addresses (source mac or
430  * destination mac match) are dropped.
431  *
432  * @cliexpar
433  * Example of how to add a dynamic MAC Address entry to the L2 FIB table
434  * of a bridge-domain (where 200 is the bridge-domain-id):
435  * @cliexcmd{l2fib add 52:54:00:53:18:33 200 GigabitEthernet0/8/0.200}
436  * Example of how to add a static MAC Address entry to the L2 FIB table
437  * of a bridge-domain (where 200 is the bridge-domain-id):
438  * @cliexcmd{l2fib add 52:54:00:53:18:55 200 GigabitEthernet0/8/0.200 static}
439  * Example of how to add a filter such that a packet with the given MAC
440  * Address will be dropped in a given bridge-domain (where 200 is the
441  * bridge-domain-id):
442  * @cliexcmd{l2fib add 52:54:00:53:18:77 200 filter}
443  * Example of show command of the provisioned MAC Addresses and filters:
444  * @cliexstart{show l2fib verbose}
445  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
446  * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
447  * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
448  * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
449  * 3 l2fib entries
450  * @cliexend
451 ?*/
452 /* *INDENT-OFF* */
453 VLIB_CLI_COMMAND (l2fib_add_cli, static) = {
454  .path = "l2fib add",
455  .short_help = "l2fib add <mac> <bridge-domain-id> filter | <intf> [static | bvi]",
456  .function = l2fib_add,
457 };
458 /* *INDENT-ON* */
459 
460 
461 static clib_error_t *
463  unformat_input_t * input, vlib_cli_command_t * cmd)
464 {
465  clib_error_t *error = 0;
466  u64 mac, save_mac;
467  u32 bd_index = 0;
468  u32 sw_if_index = 8;
469  u32 filter_mac = 0;
470  u32 bvi_mac = 0;
471  u32 is_add = 0;
472  u32 is_del = 0;
473  u32 is_check = 0;
474  u32 count = 1;
475  int mac_set = 0;
476  int i;
477 
479  {
480  if (unformat (input, "mac %U", unformat_ethernet_address, &mac))
481  mac_set = 1;
482  else if (unformat (input, "add"))
483  is_add = 1;
484  else if (unformat (input, "del"))
485  is_del = 1;
486  else if (unformat (input, "check"))
487  is_check = 1;
488  else if (unformat (input, "count %d", &count))
489  ;
490  else
491  break;
492  }
493 
494  if (mac_set == 0)
495  return clib_error_return (0, "mac not set");
496 
497  if (is_add == 0 && is_del == 0 && is_check == 0)
498  return clib_error_return (0,
499  "noop: pick at least one of (add,del,check)");
500 
501  save_mac = mac;
502 
503  if (is_add)
504  {
505  for (i = 0; i < count; i++)
506  {
507  u64 tmp;
508  l2fib_add_entry (mac, bd_index, sw_if_index, mac,
509  filter_mac, bvi_mac);
510  tmp = clib_net_to_host_u64 (mac);
511  tmp >>= 16;
512  tmp++;
513  tmp <<= 16;
514  mac = clib_host_to_net_u64 (tmp);
515  }
516  }
517 
518  if (is_check)
519  {
520  BVT (clib_bihash_kv) kv;
521  l2fib_main_t *mp = &l2fib_main;
522 
523  mac = save_mac;
524 
525  for (i = 0; i < count; i++)
526  {
527  u64 tmp;
528  kv.key = l2fib_make_key ((u8 *) & mac, bd_index);
529  if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
530  {
531  clib_warning ("key %U AWOL", format_ethernet_address, &mac);
532  break;
533  }
534  tmp = clib_net_to_host_u64 (mac);
535  tmp >>= 16;
536  tmp++;
537  tmp <<= 16;
538  mac = clib_host_to_net_u64 (tmp);
539  }
540  }
541 
542  if (is_del)
543  {
544  for (i = 0; i < count; i++)
545  {
546  u64 tmp;
547 
548  l2fib_del_entry (mac, bd_index);
549 
550  tmp = clib_net_to_host_u64 (mac);
551  tmp >>= 16;
552  tmp++;
553  tmp <<= 16;
554  mac = clib_host_to_net_u64 (tmp);
555  }
556  }
557 
558  return error;
559 }
560 
561 /*?
562  * The set of '<em>test l2fib</em>' commands allow the L2 FIB table of the default
563  * bridge domain (bridge-domain-id of 0) to be modified.
564  *
565  * @cliexpar
566  * @parblock
567  * Example of how to add a set of 4 sequential MAC Address entries to L2
568  * FIB table of the default bridge-domain:
569  * @cliexcmd{test l2fib add mac 52:54:00:53:00:00 count 4}
570  *
571  * Show the set of 4 sequential MAC Address entries that were added:
572  * @cliexstart{show l2fib verbose}
573  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
574  * 52:54:00:53:00:00 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
575  * 52:54:00:53:00:01 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
576  * 52:54:00:53:00:03 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
577  * 52:54:00:53:00:02 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
578  * 4 l2fib entries
579  * @cliexend
580  *
581  * Example of how to check that the set of 4 sequential MAC Address
582  * entries were added to L2 FIB table of the default
583  * bridge-domain. Used a count of 5 to produce an error:
584  *
585  * @cliexcmd{test l2fib check mac 52:54:00:53:00:00 count 5}
586  * The output of the check command is in the log files. Log file
587  * location may vary based on your OS and Version:
588  *
589  * <b><em># tail -f /var/log/messages | grep l2fib_test_command_fn</em></b>
590  *
591  * Sep 7 17:15:24 localhost vnet[4952]: l2fib_test_command_fn:446: key 52:54:00:53:00:04 AWOL
592  *
593  * Example of how to delete a set of 4 sequential MAC Address entries
594  * from L2 FIB table of the default bridge-domain:
595  * @cliexcmd{test l2fib del mac 52:54:00:53:00:00 count 4}
596  * @endparblock
597 ?*/
598 /* *INDENT-OFF* */
599 VLIB_CLI_COMMAND (l2fib_test_command, static) = {
600  .path = "test l2fib",
601  .short_help = "test l2fib [add|del|check] mac <base-addr> count <nn>",
602  .function = l2fib_test_command_fn,
603 };
604 /* *INDENT-ON* */
605 
606 
607 /**
608  * Delete an entry from the l2fib.
609  * Return 0 if the entry was deleted, or 1 if it was not found
610  */
611 u32
612 l2fib_del_entry (u64 mac, u32 bd_index)
613 {
614 
615  l2fib_entry_result_t result;
616  l2fib_main_t *mp = &l2fib_main;
617  BVT (clib_bihash_kv) kv;
618 
619  /* set up key */
620  kv.key = l2fib_make_key ((u8 *) & mac, bd_index);
621 
622  if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
623  return 1;
624 
625  result.raw = kv.value;
626 
627  /* decrement counter if dynamically learned mac */
628  if (result.fields.static_mac)
629  {
631  {
633  }
634  }
635 
636  /* Remove entry from hash table */
637  BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ );
638  return 0;
639 }
640 
641 /**
642  * Delete an entry from the L2FIB.
643  * The CLI format is:
644  * l2fib del <mac> <bd-id>
645  */
646 static clib_error_t *
648  unformat_input_t * input, vlib_cli_command_t * cmd)
649 {
650  bd_main_t *bdm = &bd_main;
651  clib_error_t *error = 0;
652  u64 mac;
653  u32 bd_id;
654  u32 bd_index;
655  uword *p;
656 
657  if (!unformat_user (input, unformat_ethernet_address, &mac))
658  {
659  error = clib_error_return (0, "expected mac address `%U'",
660  format_unformat_error, input);
661  goto done;
662  }
663 
664  if (!unformat (input, "%d", &bd_id))
665  {
666  error = clib_error_return (0, "expected bridge domain ID `%U'",
667  format_unformat_error, input);
668  goto done;
669  }
670 
671  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
672  if (!p)
673  {
674  error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
675  goto done;
676  }
677  bd_index = p[0];
678 
679  /* Delete the entry */
680  if (l2fib_del_entry (mac, bd_index))
681  {
682  error = clib_error_return (0, "mac entry not found");
683  goto done;
684  }
685 
686 done:
687  return error;
688 }
689 
690 /*?
691  * This command deletes an existing MAC Address entry from the L2 FIB
692  * table of an existing bridge-domain.
693  *
694  * @cliexpar
695  * 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):
696  * @cliexcmd{l2fib del 52:54:00:53:18:33 200}
697 ?*/
698 /* *INDENT-OFF* */
699 VLIB_CLI_COMMAND (l2fib_del_cli, static) = {
700  .path = "l2fib del",
701  .short_help = "l2fib del <mac> <bridge-domain-id>",
702  .function = l2fib_del,
703 };
704 /* *INDENT-ON* */
705 
706 
707 BVT (clib_bihash) * get_mac_table (void)
708 {
709  l2fib_main_t *mp = &l2fib_main;
710  return &mp->mac_table;
711 }
712 
713 static uword
715  vlib_frame_t * f)
716 {
717  uword event_type, *event_data = 0;
718  l2fib_main_t *msm = &l2fib_main;
719  l2_bridge_domain_t *bd_config;
720  BVT (clib_bihash) * h = &msm->mac_table;
722  BVT (clib_bihash_value) * v;
723  l2fib_entry_key_t key;
724  l2fib_entry_result_t result;
725  int i, j, k;
726  bool enabled = 0;
727  f64 start_time, last_run_duration = 0, t;
728  i16 delta;
729 
730  while (1)
731  {
732  if (enabled)
733  vlib_process_wait_for_event_or_clock (vm, 60 - last_run_duration);
734  else
736 
737  event_type = vlib_process_get_events (vm, &event_data);
738  vec_reset_length (event_data);
739 
740  switch (event_type)
741  {
742  case ~0:
743  break;
745  enabled = 1;
746  break;
748  enabled = 0;
749  continue;
750  default:
751  ASSERT (0);
752  }
753  last_run_duration = start_time = vlib_time_now (vm);
754  for (i = 0; i < h->nbuckets; i++)
755  {
756  /* Allow no more than 10us without a pause */
757  t = vlib_time_now (vm);
758  if (t > start_time + 10e-6)
759  {
760  vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
761  start_time = vlib_time_now (vm);
762  }
763 
764  if (i < (h->nbuckets - 3))
765  {
766  b = &h->buckets[i + 3];
768  b = &h->buckets[i + 1];
769  if (b->offset)
770  {
771  v = BV (clib_bihash_get_value) (h, b->offset);
773  }
774  }
775 
776  b = &h->buckets[i];
777  if (b->offset == 0)
778  continue;
779  v = BV (clib_bihash_get_value) (h, b->offset);
780  for (j = 0; j < (1 << b->log2_pages); j++)
781  {
782  for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
783  {
784  if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL)
785  continue;
786 
787  key.raw = v->kvp[k].key;
788  result.raw = v->kvp[k].value;
789 
790  if (result.fields.static_mac)
791  continue;
792 
794  key.fields.bd_index);
795 
796  if (bd_config->mac_age == 0)
797  continue;
798 
799  delta = (u8) (start_time / 60) - result.fields.timestamp;
800  delta += delta < 0 ? 256 : 0;
801 
802  if (delta > bd_config->mac_age)
803  {
804  void *p = &key.fields.mac;
805  l2fib_del_entry (*(u64 *) p, key.fields.bd_index);
806  }
807  }
808  v++;
809  }
810  }
811  last_run_duration = vlib_time_now (vm) - last_run_duration;
812  }
813  return 0;
814 }
815 
816 /* *INDENT-OFF* */
818  .function = l2fib_mac_age_scanner_process,
819  .type = VLIB_NODE_TYPE_PROCESS,
820  .name = "l2fib-mac-age-scanner-process",
821 };
822 /* *INDENT-ON* */
823 
824 clib_error_t *
826 {
827  l2fib_main_t *mp = &l2fib_main;
828  l2fib_entry_key_t test_key;
829  u8 test_mac[6];
830 
831  mp->vlib_main = vm;
832  mp->vnet_main = vnet_get_main ();
833 
834  /* Create the hash table */
835  BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
837 
838  /* verify the key constructor is good, since it is endian-sensitive */
839  memset (test_mac, 0, sizeof (test_mac));
840  test_mac[0] = 0x11;
841  test_key.raw = 0;
842  test_key.raw = l2fib_make_key ((u8 *) & test_mac, 0x1234);
843  ASSERT (test_key.fields.mac[0] == 0x11);
844  ASSERT (test_key.fields.bd_index == 0x1234);
845 
846  return 0;
847 }
848 
850 
851 /*
852  * fd.io coding-style-patch-verification: ON
853  *
854  * Local Variables:
855  * eval: (c-set-style "gnu")
856  * End:
857  */
struct l2fib_entry_key_t::@189::@191 fields
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:462
u32 global_learn_count
Definition: l2_learn.h:32
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
u8 * format_vnet_sw_if_index_name_with_NA(u8 *s, va_list *args)
Format sw_if_index.
Definition: l2_fib.c:60
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
clib_bihash_bucket_t
Definition: bihash_doc.h:65
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:684
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:604
void clib_bihash_free(clib_bihash *h)
Destroy a bounded index extensible hash table.
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
u32 l2fib_del_entry(u64 mac, u32 bd_index)
Delete an entry from the l2fib.
Definition: l2_fib.c:612
clib_error_t * l2fib_init(vlib_main_t *vm)
Definition: l2_fib.c:825
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define L2FIB_MEMORY_SIZE
Definition: l2_fib.h:28
unformat_function_t unformat_vnet_sw_interface
Definition: l2_fib.h:56
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:647
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
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:432
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
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.
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
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:527
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:1599
uword * bd_index_by_bd_id
Definition: l2_bd.h:27
#define hash_get(h, key)
Definition: hash.h:248
format_function_t format_vnet_sw_interface_name
#define v
Definition: acl.c:314
#define BIHASH_KVP_PER_PAGE
Definition: bihash_24_8.h:18
struct l2fib_entry_result_t::@193::@195 fields
vnet_main_t vnet_main
Definition: misc.c:43
#define L2FIB_NUM_BUCKETS
Definition: l2_fib.h:27
void clib_bihash_init(clib_bihash *h, char *name, u32 nbuckets, uword memory_size)
initialize a bounded index extensible hash table
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
l2fib_main_t l2fib_main
Definition: l2_fib.c:55
u64 raw
Definition: l2_fib.h:71
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:282
BVT(clib_bihash)
Definition: l2_fib.c:707
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:113
void l2fib_clear_table(uint keep_static)
Definition: l2_fib.c:259
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
void l2fib_add_entry(u64 mac, u32 bd_index, u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac)
Add an entry to the l2fib.
Definition: l2_fib.c:314
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:245
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
int clib_bihash_search(clib_bihash *h, clib_bihash_kv *search_v, clib_bihash_kv *return_v)
Search a bi-hash table.
Definition: l2_fib.h:33
static uword l2fib_mac_age_scanner_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: l2_fib.c:714
u64 uword
Definition: types.h:112
template key/value backing page structure
Definition: bihash_doc.h:44
l2input_main_t l2input_main
Definition: l2_input.c:87
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static u64 l2fib_make_key(u8 *mac_address, u16 bd_index)
Definition: l2_fib.h:97
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:69
void l2fib_table_dump(u32 bd_index, l2fib_entry_key_t **l2fe_key, l2fib_entry_result_t **l2fe_res)
Definition: l2_fib.c:73
short i16
Definition: types.h:46
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
l2learn_main_t l2learn_main
Definition: l2_learn.h:46
static void * clib_bihash_get_value(clib_bihash *h, uword offset)
Get pointer to value page given its clib mheap offset.
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
bd_main_t bd_main
Definition: l2_bd.c:44
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
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:354
vlib_node_registration_t l2fib_mac_age_scanner_process_node
(constructor) VLIB_REGISTER_NODE (l2fib_mac_age_scanner_process_node)
Definition: l2_fib.c:817
u64 raw
Definition: l2_fib.h:47