FD.io VPP  v17.04-9-g99c0734
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%=7s%=8s%=9s%=7s%=7s%=5s%=30s",
172  "Mac-Address", "BD-Idx", "If-Idx",
173  "BSN-ISN", "Age(min)", "static", "filter",
174  "bvi", "Interface-Name");
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 && !result.fields.static_mac)
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, "-");
194 
195  vlib_cli_output (vm,
196  "%=19U%=7d%=7d %3d/%-3d%=9v%=7s%=7s%=5s%=30U",
198  key.fields.bd_index,
199  result.fields.sw_if_index == ~0
200  ? -1 : result.fields.sw_if_index,
201  result.fields.bd_sn, result.fields.int_sn,
202  s, result.fields.static_mac ? "*" : "-",
203  result.fields.filter ? "*" : "-",
204  result.fields.bvi ? "*" : "-",
206  msm->vnet_main, result.fields.sw_if_index);
207  vec_reset_length (s);
208  }
209  total_entries++;
210  }
211  v++;
212  }
213  }
214 
215  if (total_entries == 0)
216  vlib_cli_output (vm, "no l2fib entries");
217  else
218  vlib_cli_output (vm, "%lld l2fib entries", total_entries);
219 
220  if (raw)
221  vlib_cli_output (vm, "Raw Hash Table:\n%U\n",
222  BV (format_bihash), h, 1 /* verbose */ );
223 
224  vec_free (s);
225  return 0;
226 }
227 
228 /*?
229  * This command dispays the MAC Address entries of the L2 FIB table.
230  * Output can be filtered to just get the number of MAC Addresses or display
231  * each MAC Address for all bridge domains or just a single bridge domain.
232  *
233  * @cliexpar
234  * Example of how to display the number of MAC Address entries in the L2
235  * FIB table:
236  * @cliexstart{show l2fib}
237  * 3 l2fib entries
238  * @cliexend
239  * Example of how to display all the MAC Address entries in the L2
240  * FIB table:
241  * @cliexstart{show l2fib verbose}
242  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
243  * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
244  * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
245  * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
246  * 3 l2fib entries
247  * @cliexend
248 ?*/
249 /* *INDENT-OFF* */
250 VLIB_CLI_COMMAND (show_l2fib_cli, static) = {
251  .path = "show l2fib",
252  .short_help = "show l2fib [verbose | bd_id <nn> | bd_index <nn> | raw]",
253  .function = show_l2fib,
254 };
255 /* *INDENT-ON* */
256 
257 
258 /* Remove all entries from the l2fib */
259 void
260 l2fib_clear_table (uint keep_static)
261 {
262  l2fib_main_t *mp = &l2fib_main;
263 
264  if (keep_static)
265  {
266  /* TODO: remove only non-static entries */
267  }
268  else
269  {
270  /* Remove all entries */
271  BV (clib_bihash_free) (&mp->mac_table);
272  BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
274  }
275 
277 }
278 
279 /** Clear all entries in L2FIB.
280  * @TODO: Later we may want a way to remove only the non-static entries
281  */
282 static clib_error_t *
284  unformat_input_t * input, vlib_cli_command_t * cmd)
285 {
286  l2fib_clear_table (0);
287  return 0;
288 }
289 
290 /*?
291  * This command clears all the MAC Address entries from the L2 FIB table.
292  *
293  * @cliexpar
294  * Example of how to clear the L2 FIB Table:
295  * @cliexcmd{clear l2fib}
296  * Example to show the L2 FIB Table has been cleared:
297  * @cliexstart{show l2fib verbose}
298  * no l2fib entries
299  * @cliexend
300 ?*/
301 /* *INDENT-OFF* */
302 VLIB_CLI_COMMAND (clear_l2fib_cli, static) = {
303  .path = "clear l2fib",
304  .short_help = "clear l2fib",
305  .function = clear_l2fib,
306 };
307 /* *INDENT-ON* */
308 
309 
310 /**
311  * Add an entry to the l2fib.
312  * If the entry already exists then overwrite it
313  */
314 void
316  u32 bd_index,
317  u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac)
318 {
319  l2fib_entry_key_t key;
320  l2fib_entry_result_t result;
321  __attribute__ ((unused)) u32 bucket_contents;
322  l2fib_main_t *mp = &l2fib_main;
323  BVT (clib_bihash_kv) kv;
324 
325  /* set up key */
326  key.raw = l2fib_make_key ((u8 *) & mac, bd_index);
327 
328  /* set up result */
329  result.raw = 0; /* clear all fields */
330  result.fields.sw_if_index = sw_if_index;
331  result.fields.static_mac = static_mac;
332  result.fields.filter = filter_mac;
333  result.fields.bvi = bvi_mac;
334  if (!static_mac)
335  {
336  l2_input_config_t *int_config = l2input_intf_config (sw_if_index);
337  l2_bridge_domain_t *bd_config =
339  bd_index);
340  result.fields.int_sn = int_config->seq_num;
341  result.fields.bd_sn = bd_config->seq_num;
342  }
343 
344  kv.key = key.raw;
345  kv.value = result.raw;
346 
347  BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ );
348 
349  /* increment counter if dynamically learned mac */
350  if (result.fields.static_mac)
351  {
353  }
354 }
355 
356 /**
357  * Add an entry to the L2FIB.
358  * The CLI format is:
359  * l2fib add <mac> <bd> <intf> [static] [bvi]
360  * l2fib add <mac> <bd> filter
361  * Note that filter and bvi entries are always static
362  */
363 static clib_error_t *
365  unformat_input_t * input, vlib_cli_command_t * cmd)
366 {
367  bd_main_t *bdm = &bd_main;
368  vnet_main_t *vnm = vnet_get_main ();
369  clib_error_t *error = 0;
370  u64 mac;
371  u32 bd_id;
372  u32 bd_index;
373  u32 sw_if_index = ~0;
374  u32 filter_mac = 0;
375  u32 static_mac = 0;
376  u32 bvi_mac = 0;
377  uword *p;
378 
379  if (!unformat_user (input, unformat_ethernet_address, &mac))
380  {
381  error = clib_error_return (0, "expected mac address `%U'",
382  format_unformat_error, input);
383  goto done;
384  }
385 
386  if (!unformat (input, "%d", &bd_id))
387  {
388  error = clib_error_return (0, "expected bridge domain ID `%U'",
389  format_unformat_error, input);
390  goto done;
391  }
392 
393  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
394  if (!p)
395  {
396  error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
397  goto done;
398  }
399  bd_index = p[0];
400 
401  if (unformat (input, "filter"))
402  {
403  filter_mac = 1;
404  static_mac = 1;
405 
406  }
407  else
408  {
409 
410  if (!unformat_user
411  (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
412  {
413  error = clib_error_return (0, "unknown interface `%U'",
414  format_unformat_error, input);
415  goto done;
416  }
417  if (unformat (input, "static"))
418  {
419  static_mac = 1;
420  }
421  else if (unformat (input, "bvi"))
422  {
423  bvi_mac = 1;
424  static_mac = 1;
425  }
426  }
427 
428  l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac,
429  bvi_mac);
430 
431 done:
432  return error;
433 }
434 
435 /*?
436  * This command adds a MAC Address entry to the L2 FIB table
437  * of an existing bridge-domain. The MAC Address can be static
438  * or dynamic. This command also allows a filter to be added,
439  * such that packets with given MAC Addresses (source mac or
440  * destination mac match) are dropped.
441  *
442  * @cliexpar
443  * Example of how to add a dynamic MAC Address entry to the L2 FIB table
444  * of a bridge-domain (where 200 is the bridge-domain-id):
445  * @cliexcmd{l2fib add 52:54:00:53:18:33 200 GigabitEthernet0/8/0.200}
446  * Example of how to add a static MAC Address entry to the L2 FIB table
447  * of a bridge-domain (where 200 is the bridge-domain-id):
448  * @cliexcmd{l2fib add 52:54:00:53:18:55 200 GigabitEthernet0/8/0.200 static}
449  * Example of how to add a filter such that a packet with the given MAC
450  * Address will be dropped in a given bridge-domain (where 200 is the
451  * bridge-domain-id):
452  * @cliexcmd{l2fib add 52:54:00:53:18:77 200 filter}
453  * Example of show command of the provisioned MAC Addresses and filters:
454  * @cliexstart{show l2fib verbose}
455  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
456  * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
457  * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
458  * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
459  * 3 l2fib entries
460  * @cliexend
461 ?*/
462 /* *INDENT-OFF* */
463 VLIB_CLI_COMMAND (l2fib_add_cli, static) = {
464  .path = "l2fib add",
465  .short_help = "l2fib add <mac> <bridge-domain-id> filter | <intf> [static | bvi]",
466  .function = l2fib_add,
467 };
468 /* *INDENT-ON* */
469 
470 
471 static clib_error_t *
473  unformat_input_t * input, vlib_cli_command_t * cmd)
474 {
475  clib_error_t *error = 0;
476  u64 mac, save_mac;
477  u32 bd_index = 0;
478  u32 sw_if_index = 8;
479  u32 filter_mac = 0;
480  u32 bvi_mac = 0;
481  u32 is_add = 0;
482  u32 is_del = 0;
483  u32 is_check = 0;
484  u32 count = 1;
485  int mac_set = 0;
486  int i;
487 
489  {
490  if (unformat (input, "mac %U", unformat_ethernet_address, &mac))
491  mac_set = 1;
492  else if (unformat (input, "add"))
493  is_add = 1;
494  else if (unformat (input, "del"))
495  is_del = 1;
496  else if (unformat (input, "check"))
497  is_check = 1;
498  else if (unformat (input, "count %d", &count))
499  ;
500  else
501  break;
502  }
503 
504  if (mac_set == 0)
505  return clib_error_return (0, "mac not set");
506 
507  if (is_add == 0 && is_del == 0 && is_check == 0)
508  return clib_error_return (0,
509  "noop: pick at least one of (add,del,check)");
510 
511  save_mac = mac;
512 
513  if (is_add)
514  {
515  for (i = 0; i < count; i++)
516  {
517  u64 tmp;
518  l2fib_add_entry (mac, bd_index, sw_if_index, mac,
519  filter_mac, bvi_mac);
520  tmp = clib_net_to_host_u64 (mac);
521  tmp >>= 16;
522  tmp++;
523  tmp <<= 16;
524  mac = clib_host_to_net_u64 (tmp);
525  }
526  }
527 
528  if (is_check)
529  {
530  BVT (clib_bihash_kv) kv;
531  l2fib_main_t *mp = &l2fib_main;
532 
533  mac = save_mac;
534 
535  for (i = 0; i < count; i++)
536  {
537  u64 tmp;
538  kv.key = l2fib_make_key ((u8 *) & mac, bd_index);
539  if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
540  {
541  clib_warning ("key %U AWOL", format_ethernet_address, &mac);
542  break;
543  }
544  tmp = clib_net_to_host_u64 (mac);
545  tmp >>= 16;
546  tmp++;
547  tmp <<= 16;
548  mac = clib_host_to_net_u64 (tmp);
549  }
550  }
551 
552  if (is_del)
553  {
554  for (i = 0; i < count; i++)
555  {
556  u64 tmp;
557 
558  l2fib_del_entry (mac, bd_index);
559 
560  tmp = clib_net_to_host_u64 (mac);
561  tmp >>= 16;
562  tmp++;
563  tmp <<= 16;
564  mac = clib_host_to_net_u64 (tmp);
565  }
566  }
567 
568  return error;
569 }
570 
571 /*?
572  * The set of '<em>test l2fib</em>' commands allow the L2 FIB table of the default
573  * bridge domain (bridge-domain-id of 0) to be modified.
574  *
575  * @cliexpar
576  * @parblock
577  * Example of how to add a set of 4 sequential MAC Address entries to L2
578  * FIB table of the default bridge-domain:
579  * @cliexcmd{test l2fib add mac 52:54:00:53:00:00 count 4}
580  *
581  * Show the set of 4 sequential MAC Address entries that were added:
582  * @cliexstart{show l2fib verbose}
583  * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
584  * 52:54:00:53:00:00 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
585  * 52:54:00:53:00:01 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
586  * 52:54:00:53:00:03 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
587  * 52:54:00:53:00:02 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
588  * 4 l2fib entries
589  * @cliexend
590  *
591  * Example of how to check that the set of 4 sequential MAC Address
592  * entries were added to L2 FIB table of the default
593  * bridge-domain. Used a count of 5 to produce an error:
594  *
595  * @cliexcmd{test l2fib check mac 52:54:00:53:00:00 count 5}
596  * The output of the check command is in the log files. Log file
597  * location may vary based on your OS and Version:
598  *
599  * <b><em># tail -f /var/log/messages | grep l2fib_test_command_fn</em></b>
600  *
601  * Sep 7 17:15:24 localhost vnet[4952]: l2fib_test_command_fn:446: key 52:54:00:53:00:04 AWOL
602  *
603  * Example of how to delete a set of 4 sequential MAC Address entries
604  * from L2 FIB table of the default bridge-domain:
605  * @cliexcmd{test l2fib del mac 52:54:00:53:00:00 count 4}
606  * @endparblock
607 ?*/
608 /* *INDENT-OFF* */
609 VLIB_CLI_COMMAND (l2fib_test_command, static) = {
610  .path = "test l2fib",
611  .short_help = "test l2fib [add|del|check] mac <base-addr> count <nn>",
612  .function = l2fib_test_command_fn,
613 };
614 /* *INDENT-ON* */
615 
616 
617 /**
618  * Delete an entry from the l2fib.
619  * Return 0 if the entry was deleted, or 1 if it was not found
620  */
621 u32
622 l2fib_del_entry (u64 mac, u32 bd_index)
623 {
624 
625  l2fib_entry_result_t result;
626  l2fib_main_t *mp = &l2fib_main;
627  BVT (clib_bihash_kv) kv;
628 
629  /* set up key */
630  kv.key = l2fib_make_key ((u8 *) & mac, bd_index);
631 
632  if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
633  return 1;
634 
635  result.raw = kv.value;
636 
637  /* decrement counter if dynamically learned mac */
638  if (result.fields.static_mac)
639  {
641  {
643  }
644  }
645 
646  /* Remove entry from hash table */
647  BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ );
648  return 0;
649 }
650 
651 /**
652  * Delete an entry from the L2FIB.
653  * The CLI format is:
654  * l2fib del <mac> <bd-id>
655  */
656 static clib_error_t *
658  unformat_input_t * input, vlib_cli_command_t * cmd)
659 {
660  bd_main_t *bdm = &bd_main;
661  clib_error_t *error = 0;
662  u64 mac;
663  u32 bd_id;
664  u32 bd_index;
665  uword *p;
666 
667  if (!unformat_user (input, unformat_ethernet_address, &mac))
668  {
669  error = clib_error_return (0, "expected mac address `%U'",
670  format_unformat_error, input);
671  goto done;
672  }
673 
674  if (!unformat (input, "%d", &bd_id))
675  {
676  error = clib_error_return (0, "expected bridge domain ID `%U'",
677  format_unformat_error, input);
678  goto done;
679  }
680 
681  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
682  if (!p)
683  {
684  error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
685  goto done;
686  }
687  bd_index = p[0];
688 
689  /* Delete the entry */
690  if (l2fib_del_entry (mac, bd_index))
691  {
692  error = clib_error_return (0, "mac entry not found");
693  goto done;
694  }
695 
696 done:
697  return error;
698 }
699 
700 /*?
701  * This command deletes an existing MAC Address entry from the L2 FIB
702  * table of an existing bridge-domain.
703  *
704  * @cliexpar
705  * 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):
706  * @cliexcmd{l2fib del 52:54:00:53:18:33 200}
707 ?*/
708 /* *INDENT-OFF* */
709 VLIB_CLI_COMMAND (l2fib_del_cli, static) = {
710  .path = "l2fib del",
711  .short_help = "l2fib del <mac> <bridge-domain-id>",
712  .function = l2fib_del,
713 };
714 /* *INDENT-ON* */
715 
716 /**
717  Kick off ager to scan MACs to age/delete MAC entries
718 */
719 void
721 {
722  l2_bridge_domain_t *bd_config;
723  int enable = 0;
724 
725  /* check if there is at least one bd with mac aging enabled */
726  vec_foreach (bd_config, l2input_main.bd_configs)
727  if (bd_config->bd_id != ~0 && bd_config->mac_age != 0)
728  enable = 1;
729 
733 }
734 
735 /**
736  Flush all learned MACs from an interface
737 */
738 void
740 {
741  l2_input_config_t *int_config;
742  int_config = l2input_intf_config (sw_if_index);
743  int_config->seq_num += 1;
745 }
746 
747 /**
748  Flush all learned MACs in a bridge domain
749 */
750 void
752 {
753  l2_bridge_domain_t *bd_config;
755  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
756  bd_config->seq_num += 1;
758 }
759 
760 /**
761  Flush MACs, except static ones, associated with an interface
762  The CLI format is:
763  l2fib flush-mac interface <if-name>
764 */
765 static clib_error_t *
767  unformat_input_t * input, vlib_cli_command_t * cmd)
768 {
769  vnet_main_t *vnm = vnet_get_main ();
770  clib_error_t *error = 0;
771  u32 sw_if_index;
772 
773  if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
774  {
775  error = clib_error_return (0, "unknown interface `%U'",
776  format_unformat_error, input);
777  goto done;
778  }
779 
780  l2fib_flush_int_mac (vm, sw_if_index);
781 
782 done:
783  return error;
784 }
785 
786 /*?
787  * This command kick off ager to delete all existing MAC Address entries,
788  * except static ones, associated with an interface from the L2 FIB table.
789  *
790  * @cliexpar
791  * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
792  * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
793 ?*/
794 /* *INDENT-OFF* */
795 VLIB_CLI_COMMAND (l2fib_flush_mac_int_cli, static) = {
796  .path = "l2fib flush-mac interface",
797  .short_help = "l2fib flush-mac interface <if-name>",
798  .function = l2fib_flush_mac_int,
799 };
800 /* *INDENT-ON* */
801 
802 /**
803  Flush bridge-domain MACs except static ones.
804  The CLI format is:
805  l2fib flush-mac bridge-domain <bd-id>
806 */
807 static clib_error_t *
809  unformat_input_t * input, vlib_cli_command_t * cmd)
810 {
811  bd_main_t *bdm = &bd_main;
812  clib_error_t *error = 0;
813  u32 bd_index, bd_id;
814  uword *p;
815 
816  if (!unformat (input, "%d", &bd_id))
817  {
818  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
819  format_unformat_error, input);
820  goto done;
821  }
822 
823  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
824  if (p)
825  bd_index = *p;
826  else
827  return clib_error_return (0, "No such bridge domain %d", bd_id);
828 
829  l2fib_flush_bd_mac (vm, bd_index);
830 
831 done:
832  return error;
833 }
834 
835 /*?
836  * This command kick off ager to delete all existing MAC Address entries,
837  * except static ones, in a bridge domain from the L2 FIB table.
838  *
839  * @cliexpar
840  * Example of how to flush MAC Address entries learned in a bridge domain from the L2 FIB table:
841  * @cliexcmd{l2fib flush-mac bridge-domain 1000}
842 ?*/
843 /* *INDENT-OFF* */
844 VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = {
845  .path = "l2fib flush-mac bridge-domain",
846  .short_help = "l2fib flush-mac bridge-domain <bd-id>",
847  .function = l2fib_flush_mac_bd,
848 };
849 /* *INDENT-ON* */
850 
851 
852 BVT (clib_bihash) * get_mac_table (void)
853 {
854  l2fib_main_t *mp = &l2fib_main;
855  return &mp->mac_table;
856 }
857 
858 static uword
860  vlib_frame_t * f)
861 {
862  uword event_type, *event_data = 0;
863  l2fib_main_t *msm = &l2fib_main;
864  l2_input_config_t *int_config;
865  l2_bridge_domain_t *bd_config;
866  BVT (clib_bihash) * h = &msm->mac_table;
868  BVT (clib_bihash_value) * v;
869  l2fib_entry_key_t key;
870  l2fib_entry_result_t result;
871  int i, j, k;
872  bool enabled = 0;
873  f64 start_time, last_run_duration = 0, t;
874  i16 delta;
875 
876  while (1)
877  {
878  if (enabled)
879  vlib_process_wait_for_event_or_clock (vm, 60 - last_run_duration);
880  else
882 
883  event_type = vlib_process_get_events (vm, &event_data);
884  vec_reset_length (event_data);
885 
886  switch (event_type)
887  {
888  case ~0:
889  break;
891  enabled = 1;
892  break;
894  enabled = 0;
895  continue;
897  enabled = 0;
898  break;
899  default:
900  ASSERT (0);
901  }
902  last_run_duration = start_time = vlib_time_now (vm);
903  for (i = 0; i < h->nbuckets; i++)
904  {
905  /* Allow no more than 10us without a pause */
906  t = vlib_time_now (vm);
907  if (t > start_time + 10e-6)
908  {
909  vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
910  start_time = vlib_time_now (vm);
911  }
912 
913  if (i < (h->nbuckets - 3))
914  {
915  b = &h->buckets[i + 3];
917  b = &h->buckets[i + 1];
918  if (b->offset)
919  {
920  v = BV (clib_bihash_get_value) (h, b->offset);
922  }
923  }
924 
925  b = &h->buckets[i];
926  if (b->offset == 0)
927  continue;
928  v = BV (clib_bihash_get_value) (h, b->offset);
929  for (j = 0; j < (1 << b->log2_pages); j++)
930  {
931  for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
932  {
933  if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL)
934  continue;
935 
936  key.raw = v->kvp[k].key;
937  result.raw = v->kvp[k].value;
938 
939  if (result.fields.static_mac)
940  continue;
941 
942  int_config =
943  l2input_intf_config (result.fields.sw_if_index);
944  bd_config =
946  key.fields.bd_index);
947 
948  if ((result.fields.int_sn != int_config->seq_num) ||
949  (result.fields.bd_sn != bd_config->seq_num))
950  {
951  void *p = &key.fields.mac;
952  l2fib_del_entry (*(u64 *) p, key.fields.bd_index);
953  continue;
954  }
955 
956  if (bd_config->mac_age == 0)
957  continue;
958 
959  delta = (u8) (start_time / 60) - result.fields.timestamp;
960  delta += delta < 0 ? 256 : 0;
961 
962  if (delta > bd_config->mac_age)
963  {
964  void *p = &key.fields.mac;
965  l2fib_del_entry (*(u64 *) p, key.fields.bd_index);
966  }
967  }
968  v++;
969  }
970  }
971  last_run_duration = vlib_time_now (vm) - last_run_duration;
972  }
973  return 0;
974 }
975 
976 /* *INDENT-OFF* */
978  .function = l2fib_mac_age_scanner_process,
979  .type = VLIB_NODE_TYPE_PROCESS,
980  .name = "l2fib-mac-age-scanner-process",
981 };
982 /* *INDENT-ON* */
983 
984 clib_error_t *
986 {
987  l2fib_main_t *mp = &l2fib_main;
988  l2fib_entry_key_t test_key;
989  u8 test_mac[6];
990 
991  mp->vlib_main = vm;
992  mp->vnet_main = vnet_get_main ();
993 
994  /* Create the hash table */
995  BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
997 
998  /* verify the key constructor is good, since it is endian-sensitive */
999  memset (test_mac, 0, sizeof (test_mac));
1000  test_mac[0] = 0x11;
1001  test_key.raw = 0;
1002  test_key.raw = l2fib_make_key ((u8 *) & test_mac, 0x1234);
1003  ASSERT (test_key.fields.mac[0] == 0x11);
1004  ASSERT (test_key.fields.bd_index == 0x1234);
1005 
1006  return 0;
1007 }
1008 
1010 
1011 /*
1012  * fd.io coding-style-patch-verification: ON
1013  *
1014  * Local Variables:
1015  * eval: (c-set-style "gnu")
1016  * End:
1017  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
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:472
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
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:683
#define BIHASH_KVP_PER_PAGE
Definition: bihash_16_8.h:18
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:603
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
void clib_bihash_free(clib_bihash *h)
Destroy a bounded index extensible hash table.
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:472
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:185
u32 l2fib_del_entry(u64 mac, u32 bd_index)
Delete an entry from the l2fib.
Definition: l2_fib.c:622
clib_error_t * l2fib_init(vlib_main_t *vm)
Definition: l2_fib.c:985
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:982
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
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
unformat_function_t unformat_vnet_sw_interface
Definition: l2_fib.h:56
struct l2fib_entry_result_t::@150::@152 fields
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:657
#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
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:526
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define clib_error_return(e, args...)
Definition: error.h:111
unsigned long u64
Definition: types.h:89
uword * bd_index_by_bd_id
Definition: l2_bd.h:27
void l2fib_start_ager_scan(vlib_main_t *vm)
Kick off ager to scan MACs to age/delete MAC entries.
Definition: l2_fib.c:720
#define hash_get(h, key)
Definition: hash.h:248
format_function_t format_vnet_sw_interface_name
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:930
#define v
Definition: acl.c:246
struct _unformat_input_t unformat_input_t
void l2fib_flush_bd_mac(vlib_main_t *vm, u32 bd_index)
Flush all learned MACs in a bridge domain.
Definition: l2_fib.c:751
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
l2fib_main_t l2fib_main
Definition: l2_fib.c:55
u64 raw
Definition: l2_fib.h:72
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:283
BVT(clib_bihash)
Definition: l2_fib.c:852
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
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
void l2fib_clear_table(uint keep_static)
Definition: l2_fib.c:260
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:276
vec_header_t h
Definition: buffer.c:275
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
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:766
#define clib_warning(format, args...)
Definition: error.h:59
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:315
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:1654
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:227
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
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:859
u64 uword
Definition: types.h:112
template key/value backing page structure
Definition: bihash_doc.h:44
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:808
l2input_main_t l2input_main
Definition: l2_input.c:88
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:98
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:72
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
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
l2learn_main_t l2learn_main
Definition: l2_learn.h:46
struct l2fib_entry_key_t::@146::@148 fields
#define vec_foreach(var, vec)
Vector iterator.
static void * clib_bihash_get_value(clib_bihash *h, uword offset)
Get pointer to value page given its clib mheap offset.
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:364
vlib_node_registration_t l2fib_mac_age_scanner_process_node
(constructor) VLIB_REGISTER_NODE (l2fib_mac_age_scanner_process_node)
Definition: l2_fib.c:977
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:577
void l2fib_flush_int_mac(vlib_main_t *vm, u32 sw_if_index)
Flush all learned MACs from an interface.
Definition: l2_fib.c:739
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
u64 raw
Definition: l2_fib.h:47
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169