blob: efcc640d5ea305780d9a7b8e01c187fb6bda57e9 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Ed Warnickecb9cada2015-12-08 15:45:58 -070021#include <vnet/ethernet/ethernet.h>
22#include <vlib/cli.h>
23
24#include <vppinfra/error.h>
25#include <vppinfra/hash.h>
Damjan Mariond171d482016-12-05 14:16:38 +010026#include <vnet/l2/l2_input.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070027#include <vnet/l2/l2_fib.h>
28#include <vnet/l2/l2_learn.h>
29#include <vnet/l2/l2_bd.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070030#include <vppinfra/bihash_template.c>
John Lo8d00fff2017-08-03 00:35:36 -040031#include <vlibmemory/api.h>
John Lo8d00fff2017-08-03 00:35:36 -040032
Filip Tehlar5a9d2a12021-06-22 21:20:29 +000033#include <vnet/l2/l2.api_enum.h>
34#include <vnet/l2/l2.api_types.h>
John Lo8d00fff2017-08-03 00:35:36 -040035
Filip Tehlar5a9d2a12021-06-22 21:20:29 +000036#define vl_endianfun
37#include <vnet/l2/l2.api.h>
John Lo8d00fff2017-08-03 00:35:36 -040038#undef vl_endianfun
39
Billy McFall22aa3e92016-09-09 08:46:40 -040040/**
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
Ed Warnickecb9cada2015-12-08 15:45:58 -070050l2fib_main_t l2fib_main;
51
Neale Ranns7d645f72018-10-24 02:25:06 -070052u8 *
53format_l2fib_entry_result_flags (u8 * s, va_list * args)
54{
55 l2fib_entry_result_flags_t flags = va_arg (*args, int);
56
57 if (L2FIB_ENTRY_RESULT_FLAG_NONE == flags)
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 }
67 foreach_l2fib_entry_result_attr
68#undef _
69 }
70 return (s);
71}
72
Mohsin Kazmi57938f62017-10-27 21:28:07 +020073static void
74incr_mac_address (u8 * mac)
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
Dave Barach178cf492018-11-13 16:34:13 -050081 clib_memcpy_fast (mac, &tmp, 6);
Mohsin Kazmi57938f62017-10-27 21:28:07 +020082}
83
Dave Barach97d8dc22016-08-15 15:31:15 -040084/** Format sw_if_index. If the value is ~0, use the text "N/A" */
85u8 *
86format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070087{
Dave Barach97d8dc22016-08-15 15:31:15 -040088 vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070089 u32 sw_if_index = va_arg (*args, u32);
90 if (sw_if_index == ~0)
91 return format (s, "N/A");
Eyal Barib823df52017-06-12 17:07:22 +030092
Dave Barach3940de32019-07-23 16:28:36 -040093 vnet_sw_interface_t *swif =
94 vnet_get_sw_interface_or_null (vnm, sw_if_index);
Eyal Barib823df52017-06-12 17:07:22 +030095 if (!swif)
Eyal Bari0f360dc2017-06-14 13:11:20 +030096 return format (s, "Stale");
Eyal Barib823df52017-06-12 17:07:22 +030097
Vladislav Grishenkofb9d1ac2022-08-04 20:36:45 +050098 return format (s, "%U", format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -070099}
100
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700101typedef struct l2fib_dump_walk_ctx_t_
102{
103 u32 bd_index;
104 l2fib_entry_key_t *l2fe_key;
105 l2fib_entry_result_t *l2fe_res;
106} l2fib_dump_walk_ctx_t;
107
Neale Rannsf50bac12019-12-06 05:53:17 +0000108static int
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700109l2fib_dump_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
110{
111 l2fib_dump_walk_ctx_t *ctx = arg;
112 l2fib_entry_result_t result;
113 l2fib_entry_key_t key;
114
115 key.raw = kvp->key;
116 result.raw = kvp->value;
117
118 if ((ctx->bd_index == ~0) || (ctx->bd_index == key.fields.bd_index))
119 {
120 vec_add1 (ctx->l2fe_key, key);
121 vec_add1 (ctx->l2fe_res, result);
122 }
Neale Rannsf50bac12019-12-06 05:53:17 +0000123
124 return (BIHASH_WALK_CONTINUE);
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700125}
126
Dave Barach97d8dc22016-08-15 15:31:15 -0400127void
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700128l2fib_table_dump (u32 bd_index,
129 l2fib_entry_key_t ** l2fe_key,
Dave Barach97d8dc22016-08-15 15:31:15 -0400130 l2fib_entry_result_t ** l2fe_res)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131{
Dave Barach97d8dc22016-08-15 15:31:15 -0400132 l2fib_main_t *msm = &l2fib_main;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700133 l2fib_dump_walk_ctx_t ctx = {
134 .bd_index = bd_index,
135 };
136
137 BV (clib_bihash_foreach_key_value_pair)
138 (&msm->mac_table, l2fib_dump_walk_cb, &ctx);
139
140 *l2fe_key = ctx.l2fe_key;
141 *l2fe_res = ctx.l2fe_res;
142}
143
Neale Ranns47a3d992020-09-29 15:38:51 +0000144void
145l2_fib_extract_seq_num (l2fib_seq_num_t sn, u8 * bd_sn, u8 * if_sn)
146{
147 *bd_sn = sn >> 8;
148 *if_sn = sn & 0xff;
149}
150
151u8 *
152format_l2_fib_seq_num (u8 * s, va_list * a)
153{
154 l2fib_seq_num_t sn = va_arg (*a, int);
155 u8 bd_sn, if_sn;
156
157 l2_fib_extract_seq_num (sn, &bd_sn, &if_sn);
158
159 s = format (s, "%3d/%-3d", bd_sn, if_sn);
160
161 return (s);
162}
163
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700164typedef struct l2fib_show_walk_ctx_t_
165{
166 u8 first_entry;
167 u8 verbose;
168 vlib_main_t *vm;
169 vnet_main_t *vnm;
170 u32 total_entries;
171 u32 bd_index;
172 u8 learn;
173 u8 add;
174 u8 now;
175} l2fib_show_walk_ctx_t;
176
Neale Rannsf50bac12019-12-06 05:53:17 +0000177static int
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700178l2fib_show_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
179{
180 l2fib_show_walk_ctx_t *ctx = arg;
181 l2_bridge_domain_t *bd_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 l2fib_entry_result_t result;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700183 l2fib_entry_key_t key;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700185 if (ctx->verbose && ctx->first_entry)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700187 ctx->first_entry = 0;
188 vlib_cli_output (ctx->vm,
189 "%=19s%=7s%=7s%=8s%=9s%=7s%=7s%=5s%=30s",
190 "Mac-Address", "BD-Idx", "If-Idx",
191 "BSN-ISN", "Age(min)", "static", "filter",
192 "bvi", "Interface-Name");
193 }
194
195 key.raw = kvp->key;
196 result.raw = kvp->value;
197 ctx->total_entries++;
198
199 if (ctx->verbose &&
200 ((ctx->bd_index >> 31) || (ctx->bd_index == key.fields.bd_index)))
201 {
202 u8 *s = NULL;
203
Neale Rannsb54d0812018-09-06 06:22:56 -0700204 if (ctx->learn && l2fib_entry_result_is_set_AGE_NOT (&result))
Neale Rannsf50bac12019-12-06 05:53:17 +0000205 return (BIHASH_WALK_CONTINUE); /* skip provisioned macs */
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700206
Neale Rannsb54d0812018-09-06 06:22:56 -0700207 if (ctx->add && !l2fib_entry_result_is_set_AGE_NOT (&result))
Neale Rannsf50bac12019-12-06 05:53:17 +0000208 return (BIHASH_WALK_CONTINUE); /* skip learned macs */
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700209
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100210 bd_config = &vec_elt (l2input_main.bd_configs, key.fields.bd_index);
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700211
Neale Rannsb54d0812018-09-06 06:22:56 -0700212 if (l2fib_entry_result_is_set_AGE_NOT (&result))
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700213 s = format (s, "no");
214 else if (bd_config->mac_age == 0)
215 s = format (s, "-");
216 else
Dave Barach97d8dc22016-08-15 15:31:15 -0400217 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700218 i16 delta = ctx->now - result.fields.timestamp;
219 delta += delta < 0 ? 256 : 0;
220 s = format (s, "%d", delta);
Dave Barach97d8dc22016-08-15 15:31:15 -0400221 }
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700222
223 vlib_cli_output (ctx->vm,
Neale Ranns47a3d992020-09-29 15:38:51 +0000224 "%=19U%=7d%=7d %U%=9v%=7s%=7s%=5s%=30U",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700225 format_ethernet_address, key.fields.mac,
226 key.fields.bd_index,
227 result.fields.sw_if_index == ~0
228 ? -1 : result.fields.sw_if_index,
Neale Ranns47a3d992020-09-29 15:38:51 +0000229 format_l2_fib_seq_num, result.fields.sn, s,
Neale Rannsb54d0812018-09-06 06:22:56 -0700230 l2fib_entry_result_is_set_STATIC (&result) ? "*" : "-",
231 l2fib_entry_result_is_set_FILTER (&result) ? "*" : "-",
232 l2fib_entry_result_is_set_BVI (&result) ? "*" : "-",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700233 format_vnet_sw_if_index_name_with_NA,
234 ctx->vnm, result.fields.sw_if_index);
235 vec_free (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 }
Neale Rannsf50bac12019-12-06 05:53:17 +0000237
238 return (BIHASH_WALK_CONTINUE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239}
240
Chris Luke16bcf7d2016-09-01 14:31:46 -0400241/** Display the contents of the l2fib. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400243show_l2fib (vlib_main_t * vm,
244 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245{
Dave Barach97d8dc22016-08-15 15:31:15 -0400246 bd_main_t *bdm = &bd_main;
247 l2fib_main_t *msm = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 u8 raw = 0;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700249 u32 bd_id;
250 l2fib_show_walk_ctx_t ctx = {
251 .first_entry = 1,
252 .bd_index = ~0,
253 .now = (u8) (vlib_time_now (vm) / 60),
254 .vm = vm,
255 .vnm = msm->vnet_main,
256 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
John Lo7dbd7262018-05-31 10:25:18 -0400258 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
John Lo8d00fff2017-08-03 00:35:36 -0400259 {
John Lo7dbd7262018-05-31 10:25:18 -0400260 if (unformat (input, "raw"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400261 {
John Lo7dbd7262018-05-31 10:25:18 -0400262 raw = 1;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700263 ctx.verbose = 0;
John Lo7dbd7262018-05-31 10:25:18 -0400264 break;
265 }
266 else if (unformat (input, "verbose"))
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700267 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400268 else if (unformat (input, "all"))
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700269 ctx.verbose = 1;
270 else if (unformat (input, "bd_index %d", &ctx.bd_index))
271 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400272 else if (unformat (input, "learn"))
273 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700274 ctx.add = 0;
275 ctx.learn = 1;
276 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400277 }
278 else if (unformat (input, "add"))
279 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700280 ctx.learn = 0;
281 ctx.add = 1;
282 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400283 }
284 else if (unformat (input, "bd_id %d", &bd_id))
285 {
286 uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
287 if (p)
288 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700289 ctx.verbose = 1;
290 ctx.bd_index = p[0];
John Lo7dbd7262018-05-31 10:25:18 -0400291 }
292 else
293 return clib_error_return (0,
294 "bridge domain id %d doesn't exist\n",
295 bd_id);
Dave Barach97d8dc22016-08-15 15:31:15 -0400296 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 else
John Lo7dbd7262018-05-31 10:25:18 -0400298 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 }
300
Damjan Marion95147812020-09-14 12:18:44 +0200301 if (msm->mac_table_initialized == 0)
302 {
303 vlib_cli_output (vm, "no l2fib entries");
304 return 0;
305 }
306
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700307 BV (clib_bihash_foreach_key_value_pair)
308 (&msm->mac_table, l2fib_show_walk_cb, &ctx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700310 if (ctx.total_entries == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311 vlib_cli_output (vm, "no l2fib entries");
312 else
John Lo8d00fff2017-08-03 00:35:36 -0400313 {
314 l2learn_main_t *lm = &l2learn_main;
315 vlib_cli_output (vm, "L2FIB total/learned entries: %d/%d "
316 "Last scan time: %.4esec Learn limit: %d ",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700317 ctx.total_entries, lm->global_learn_count,
John Lo8d00fff2017-08-03 00:35:36 -0400318 msm->age_scan_duration, lm->global_learn_limit);
319 if (lm->client_pid)
320 vlib_cli_output (vm, "L2MAC events client PID: %d "
321 "Last e-scan time: %.4esec Delay: %.2esec "
322 "Max macs in event: %d",
323 lm->client_pid, msm->evt_scan_duration,
324 msm->event_scan_delay, msm->max_macs_in_event);
325 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326
327 if (raw)
328 vlib_cli_output (vm, "Raw Hash Table:\n%U\n",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700329 BV (format_bihash), &msm->mac_table, 1 /* verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330
331 return 0;
332}
333
Billy McFall22aa3e92016-09-09 08:46:40 -0400334/*?
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -0700335 * This command displays the MAC Address entries of the L2 FIB table.
Billy McFall22aa3e92016-09-09 08:46:40 -0400336 * Output can be filtered to just get the number of MAC Addresses or display
337 * each MAC Address for all bridge domains or just a single bridge domain.
338 *
339 * @cliexpar
340 * Example of how to display the number of MAC Address entries in the L2
341 * FIB table:
342 * @cliexstart{show l2fib}
343 * 3 l2fib entries
344 * @cliexend
345 * Example of how to display all the MAC Address entries in the L2
346 * FIB table:
John Lo7dbd7262018-05-31 10:25:18 -0400347 * @cliexstart{show l2fib all}
Billy McFall22aa3e92016-09-09 08:46:40 -0400348 * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
349 * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
350 * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
351 * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
352 * 3 l2fib entries
353 * @cliexend
354?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400355/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356VLIB_CLI_COMMAND (show_l2fib_cli, static) = {
357 .path = "show l2fib",
John Lo7dbd7262018-05-31 10:25:18 -0400358 .short_help = "show l2fib [all] | [bd_id <nn> | bd_index <nn>] [learn | add] | [raw]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 .function = show_l2fib,
360};
Dave Barach97d8dc22016-08-15 15:31:15 -0400361/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362
Damjan Marion95147812020-09-14 12:18:44 +0200363void
364l2fib_table_init (void)
365{
366 l2fib_main_t *mp = &l2fib_main;
367
368 if (mp->mac_table_initialized == 1)
369 return;
370
371 BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
372 mp->mac_table_n_buckets, mp->mac_table_memory_size);
373 mp->mac_table_initialized = 1;
374}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375
Dave Barach97d8dc22016-08-15 15:31:15 -0400376/* Remove all entries from the l2fib */
377void
Eyal Bari7537e712017-04-27 14:07:55 +0300378l2fib_clear_table (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700379{
Dave Barach97d8dc22016-08-15 15:31:15 -0400380 l2fib_main_t *mp = &l2fib_main;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100381 l2_bridge_domain_t *bd_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Damjan Marion95147812020-09-14 12:18:44 +0200383 if (mp->mac_table_initialized == 0)
384 return;
385
Matthew Smith3a97a452020-10-12 15:04:39 -0500386 mp->mac_table_initialized = 0;
387
Eyal Bari7537e712017-04-27 14:07:55 +0300388 /* Remove all entries */
389 BV (clib_bihash_free) (&mp->mac_table);
Damjan Marion95147812020-09-14 12:18:44 +0200390 l2fib_table_init ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 l2learn_main.global_learn_count = 0;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100392 vec_foreach (bd_config, l2input_main.bd_configs)
393 bd_config->learn_count = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394}
395
Chris Luke16bcf7d2016-09-01 14:31:46 -0400396/** Clear all entries in L2FIB.
397 * @TODO: Later we may want a way to remove only the non-static entries
Dave Barach97d8dc22016-08-15 15:31:15 -0400398 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400400clear_l2fib (vlib_main_t * vm,
401 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402{
Eyal Bari7537e712017-04-27 14:07:55 +0300403 l2fib_clear_table ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404 return 0;
405}
406
Billy McFall22aa3e92016-09-09 08:46:40 -0400407/*?
408 * This command clears all the MAC Address entries from the L2 FIB table.
409 *
410 * @cliexpar
411 * Example of how to clear the L2 FIB Table:
412 * @cliexcmd{clear l2fib}
413 * Example to show the L2 FIB Table has been cleared:
414 * @cliexstart{show l2fib verbose}
415 * no l2fib entries
416 * @cliexend
417?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400418/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419VLIB_CLI_COMMAND (clear_l2fib_cli, static) = {
420 .path = "clear l2fib",
Billy McFall22aa3e92016-09-09 08:46:40 -0400421 .short_help = "clear l2fib",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422 .function = clear_l2fib,
423};
Dave Barach97d8dc22016-08-15 15:31:15 -0400424/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425
Neale Ranns47a3d992020-09-29 15:38:51 +0000426static l2fib_seq_num_t
Eyal Bari7537e712017-04-27 14:07:55 +0300427l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index)
428{
Eyal Bari7537e712017-04-27 14:07:55 +0300429 l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
Neale Ranns47a3d992020-09-29 15:38:51 +0000430
431 return l2_fib_mk_seq_num (bd_config->seq_num,
432 l2_input_seq_num (sw_if_index));
Eyal Bari7537e712017-04-27 14:07:55 +0300433}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
Dave Barach97d8dc22016-08-15 15:31:15 -0400435/**
436 * Add an entry to the l2fib.
437 * If the entry already exists then overwrite it
438 */
439void
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700440l2fib_add_entry (const u8 * mac, u32 bd_index,
Neale Rannsb54d0812018-09-06 06:22:56 -0700441 u32 sw_if_index, l2fib_entry_result_flags_t flags)
Dave Barach97d8dc22016-08-15 15:31:15 -0400442{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700443 l2fib_entry_key_t key;
444 l2fib_entry_result_t result;
Dave Barach97d8dc22016-08-15 15:31:15 -0400445 __attribute__ ((unused)) u32 bucket_contents;
John Lo8d00fff2017-08-03 00:35:36 -0400446 l2fib_main_t *fm = &l2fib_main;
447 l2learn_main_t *lm = &l2learn_main;
Dave Barach97d8dc22016-08-15 15:31:15 -0400448 BVT (clib_bihash_kv) kv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700449
Damjan Marion95147812020-09-14 12:18:44 +0200450 if (fm->mac_table_initialized == 0)
451 l2fib_table_init ();
452
Dave Barach97d8dc22016-08-15 15:31:15 -0400453 /* set up key */
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200454 key.raw = l2fib_make_key (mac, bd_index);
John Lob2e73b12020-01-07 16:35:29 -0500455 kv.key = key.raw;
Dave Barach97d8dc22016-08-15 15:31:15 -0400456
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -0700457 /* check if entry already exist */
John Lo8d00fff2017-08-03 00:35:36 -0400458 if (BV (clib_bihash_search) (&fm->mac_table, &kv, &kv))
459 {
460 /* decrement counter if overwriting a learned mac */
461 result.raw = kv.value;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100462 if (!l2fib_entry_result_is_set_AGE_NOT (&result))
463 {
464 l2_bridge_domain_t *bd_config =
465 vec_elt_at_index (l2input_main.bd_configs, bd_index);
466
467 /* check if learn_count == 0 in case of race condition between 2
468 * workers adding an entry simultaneously */
469 /* learn_count variable may have little inaccuracy because they are
470 * not incremented/decremented with atomic operations */
471 /* l2fib_scan is call every 2sec fixing potential inaccuracy */
472 if (lm->global_learn_count)
473 lm->global_learn_count--;
474 if (bd_config->learn_count)
475 bd_config->learn_count--;
476 }
John Lo8d00fff2017-08-03 00:35:36 -0400477 }
478
Dave Barach97d8dc22016-08-15 15:31:15 -0400479 /* set up result */
480 result.raw = 0; /* clear all fields */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 result.fields.sw_if_index = sw_if_index;
Neale Rannsb54d0812018-09-06 06:22:56 -0700482 result.fields.flags = flags;
483
484 /* no aging for provisioned entry */
485 l2fib_entry_result_set_AGE_NOT (&result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487 kv.value = result.raw;
488
John Lo8d00fff2017-08-03 00:35:36 -0400489 BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1 /* is_add */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490}
491
Dave Barach97d8dc22016-08-15 15:31:15 -0400492/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400493 * Add an entry to the L2FIB.
Dave Barach97d8dc22016-08-15 15:31:15 -0400494 * The CLI format is:
495 * l2fib add <mac> <bd> <intf> [static] [bvi]
496 * l2fib add <mac> <bd> filter
497 * Note that filter and bvi entries are always static
498 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400500l2fib_add (vlib_main_t * vm,
501 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502{
Dave Barach97d8dc22016-08-15 15:31:15 -0400503 bd_main_t *bdm = &bd_main;
504 vnet_main_t *vnm = vnet_get_main ();
505 clib_error_t *error = 0;
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200506 u8 mac[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507 u32 bd_id;
508 u32 bd_index;
509 u32 sw_if_index = ~0;
Dave Barach97d8dc22016-08-15 15:31:15 -0400510 uword *p;
Neale Rannsb54d0812018-09-06 06:22:56 -0700511 l2fib_entry_result_flags_t flags;
512
513 flags = L2FIB_ENTRY_RESULT_FLAG_NONE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700514
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200515 if (!unformat (input, "%U", unformat_ethernet_address, mac))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700516 {
517 error = clib_error_return (0, "expected mac address `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400518 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 goto done;
520 }
Dave Barach97d8dc22016-08-15 15:31:15 -0400521
522 if (!unformat (input, "%d", &bd_id))
523 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 error = clib_error_return (0, "expected bridge domain ID `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400525 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400527 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528
529 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
Dave Barach97d8dc22016-08-15 15:31:15 -0400530 if (!p)
531 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
533 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400534 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535 bd_index = p[0];
536
Dave Barach97d8dc22016-08-15 15:31:15 -0400537 if (unformat (input, "filter"))
538 {
John Lo14edd972017-10-31 13:26:02 -0400539 l2fib_add_filter_entry (mac, bd_index);
540 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700541 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542
John Lo14edd972017-10-31 13:26:02 -0400543 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
544 {
545 error = clib_error_return (0, "unknown interface `%U'",
546 format_unformat_error, input);
547 goto done;
548 }
549
550 if (unformat (input, "static"))
Neale Rannsb54d0812018-09-06 06:22:56 -0700551 flags |= L2FIB_ENTRY_RESULT_FLAG_STATIC;
John Lo14edd972017-10-31 13:26:02 -0400552 else if (unformat (input, "bvi"))
Neale Rannsb54d0812018-09-06 06:22:56 -0700553 flags |= (L2FIB_ENTRY_RESULT_FLAG_STATIC | L2FIB_ENTRY_RESULT_FLAG_BVI);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554
John Lob2fd6cb2017-07-12 19:56:45 -0400555 if (vec_len (l2input_main.configs) <= sw_if_index)
556 {
557 error = clib_error_return (0, "Interface sw_if_index %d not in L2 mode",
558 sw_if_index);
559 goto done;
560 }
561
Neale Rannsb54d0812018-09-06 06:22:56 -0700562 l2fib_add_entry (mac, bd_index, sw_if_index, flags);
Dave Barach97d8dc22016-08-15 15:31:15 -0400563
564done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565 return error;
566}
567
Billy McFall22aa3e92016-09-09 08:46:40 -0400568/*?
569 * This command adds a MAC Address entry to the L2 FIB table
570 * of an existing bridge-domain. The MAC Address can be static
571 * or dynamic. This command also allows a filter to be added,
572 * such that packets with given MAC Addresses (source mac or
573 * destination mac match) are dropped.
574 *
575 * @cliexpar
576 * Example of how to add a dynamic MAC Address entry to the L2 FIB table
577 * of a bridge-domain (where 200 is the bridge-domain-id):
578 * @cliexcmd{l2fib add 52:54:00:53:18:33 200 GigabitEthernet0/8/0.200}
579 * Example of how to add a static MAC Address entry to the L2 FIB table
580 * of a bridge-domain (where 200 is the bridge-domain-id):
581 * @cliexcmd{l2fib add 52:54:00:53:18:55 200 GigabitEthernet0/8/0.200 static}
582 * Example of how to add a filter such that a packet with the given MAC
583 * Address will be dropped in a given bridge-domain (where 200 is the
584 * bridge-domain-id):
585 * @cliexcmd{l2fib add 52:54:00:53:18:77 200 filter}
586 * Example of show command of the provisioned MAC Addresses and filters:
587 * @cliexstart{show l2fib verbose}
588 * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
589 * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
590 * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
591 * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
592 * 3 l2fib entries
593 * @cliexend
594?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400595/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596VLIB_CLI_COMMAND (l2fib_add_cli, static) = {
597 .path = "l2fib add",
Billy McFall22aa3e92016-09-09 08:46:40 -0400598 .short_help = "l2fib add <mac> <bridge-domain-id> filter | <intf> [static | bvi]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599 .function = l2fib_add,
600};
Dave Barach97d8dc22016-08-15 15:31:15 -0400601/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602
603
604static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400605l2fib_test_command_fn (vlib_main_t * vm,
606 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607{
Damjan Marion60706a22021-10-31 19:21:31 +0100608 u8 mac[8], save_mac[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609 u32 bd_index = 0;
610 u32 sw_if_index = 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700611 u32 is_add = 0;
612 u32 is_del = 0;
613 u32 is_check = 0;
614 u32 count = 1;
615 int mac_set = 0;
616 int i;
617
Dave Barach97d8dc22016-08-15 15:31:15 -0400618 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619 {
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200620 if (unformat (input, "mac %U", unformat_ethernet_address, mac))
Dave Barach97d8dc22016-08-15 15:31:15 -0400621 mac_set = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622 else if (unformat (input, "add"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400623 is_add = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700624 else if (unformat (input, "del"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400625 is_del = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626 else if (unformat (input, "check"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400627 is_check = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 else if (unformat (input, "count %d", &count))
Dave Barach97d8dc22016-08-15 15:31:15 -0400629 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630 else
Dave Barach97d8dc22016-08-15 15:31:15 -0400631 break;
632 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633
634 if (mac_set == 0)
635 return clib_error_return (0, "mac not set");
636
637 if (is_add == 0 && is_del == 0 && is_check == 0)
Dave Barach97d8dc22016-08-15 15:31:15 -0400638 return clib_error_return (0,
639 "noop: pick at least one of (add,del,check)");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
Dave Barach178cf492018-11-13 16:34:13 -0500641 clib_memcpy_fast (save_mac, mac, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642
643 if (is_add)
644 {
645 for (i = 0; i < count; i++)
Dave Barach97d8dc22016-08-15 15:31:15 -0400646 {
Neale Rannsb54d0812018-09-06 06:22:56 -0700647 l2fib_add_entry (mac, bd_index, sw_if_index,
648 L2FIB_ENTRY_RESULT_FLAG_NONE);
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200649 incr_mac_address (mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400650 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651 }
652
653 if (is_check)
654 {
Dave Barach97d8dc22016-08-15 15:31:15 -0400655 BVT (clib_bihash_kv) kv;
656 l2fib_main_t *mp = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657
Damjan Marion95147812020-09-14 12:18:44 +0200658 if (mp->mac_table_initialized == 0)
659 return clib_error_return (0, "mac table is not initialized");
660
Dave Barach178cf492018-11-13 16:34:13 -0500661 clib_memcpy_fast (mac, save_mac, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662
663 for (i = 0; i < count; i++)
Dave Barach97d8dc22016-08-15 15:31:15 -0400664 {
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200665 kv.key = l2fib_make_key (mac, bd_index);
Dave Barach97d8dc22016-08-15 15:31:15 -0400666 if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
667 {
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200668 clib_warning ("key %U AWOL", format_ethernet_address, mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400669 break;
670 }
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200671 incr_mac_address (mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400672 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 }
674
675 if (is_del)
676 {
Dave Barach178cf492018-11-13 16:34:13 -0500677 clib_memcpy_fast (mac, save_mac, 6);
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200678
Ed Warnickecb9cada2015-12-08 15:45:58 -0700679 for (i = 0; i < count; i++)
Dave Barach97d8dc22016-08-15 15:31:15 -0400680 {
John Lo7dbd7262018-05-31 10:25:18 -0400681 l2fib_del_entry (mac, bd_index, 0);
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200682 incr_mac_address (mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400683 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 }
685
Damjan Marion95147812020-09-14 12:18:44 +0200686 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687}
688
Billy McFall22aa3e92016-09-09 08:46:40 -0400689/*?
690 * The set of '<em>test l2fib</em>' commands allow the L2 FIB table of the default
691 * bridge domain (bridge-domain-id of 0) to be modified.
692 *
693 * @cliexpar
694 * @parblock
695 * Example of how to add a set of 4 sequential MAC Address entries to L2
696 * FIB table of the default bridge-domain:
697 * @cliexcmd{test l2fib add mac 52:54:00:53:00:00 count 4}
698 *
699 * Show the set of 4 sequential MAC Address entries that were added:
700 * @cliexstart{show l2fib verbose}
701 * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
702 * 52:54:00:53:00:00 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
703 * 52:54:00:53:00:01 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
704 * 52:54:00:53:00:03 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
705 * 52:54:00:53:00:02 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
706 * 4 l2fib entries
707 * @cliexend
708 *
709 * Example of how to check that the set of 4 sequential MAC Address
710 * entries were added to L2 FIB table of the default
711 * bridge-domain. Used a count of 5 to produce an error:
712 *
713 * @cliexcmd{test l2fib check mac 52:54:00:53:00:00 count 5}
714 * The output of the check command is in the log files. Log file
715 * location may vary based on your OS and Version:
716 *
717 * <b><em># tail -f /var/log/messages | grep l2fib_test_command_fn</em></b>
718 *
719 * Sep 7 17:15:24 localhost vnet[4952]: l2fib_test_command_fn:446: key 52:54:00:53:00:04 AWOL
720 *
721 * Example of how to delete a set of 4 sequential MAC Address entries
722 * from L2 FIB table of the default bridge-domain:
723 * @cliexcmd{test l2fib del mac 52:54:00:53:00:00 count 4}
724 * @endparblock
725?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400726/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727VLIB_CLI_COMMAND (l2fib_test_command, static) = {
728 .path = "test l2fib",
Billy McFall22aa3e92016-09-09 08:46:40 -0400729 .short_help = "test l2fib [add|del|check] mac <base-addr> count <nn>",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700730 .function = l2fib_test_command_fn,
731};
Dave Barach97d8dc22016-08-15 15:31:15 -0400732/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733
734
Dave Barach97d8dc22016-08-15 15:31:15 -0400735/**
736 * Delete an entry from the l2fib.
John Lo7dbd7262018-05-31 10:25:18 -0400737 * Return 0 if the entry was deleted, or 1 it was not found or if
738 * sw_if_index is non-zero and does not match that in the entry.
Dave Barach97d8dc22016-08-15 15:31:15 -0400739 */
John Lo7dbd7262018-05-31 10:25:18 -0400740u32
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700741l2fib_del_entry (const u8 * mac, u32 bd_index, u32 sw_if_index)
Dave Barach97d8dc22016-08-15 15:31:15 -0400742{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700743 l2fib_entry_result_t result;
Dave Barach97d8dc22016-08-15 15:31:15 -0400744 l2fib_main_t *mp = &l2fib_main;
745 BVT (clib_bihash_kv) kv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746
Damjan Marion95147812020-09-14 12:18:44 +0200747 if (mp->mac_table_initialized == 0)
748 return 1;
749
Dave Barach97d8dc22016-08-15 15:31:15 -0400750 /* set up key */
John Lo7dbd7262018-05-31 10:25:18 -0400751 kv.key = l2fib_make_key (mac, bd_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752
Dave Barach97d8dc22016-08-15 15:31:15 -0400753 if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754 return 1;
755
756 result.raw = kv.value;
757
John Lo7dbd7262018-05-31 10:25:18 -0400758 /* check if sw_if_index of entry match */
759 if ((sw_if_index != 0) && (sw_if_index != result.fields.sw_if_index))
760 return 1;
761
Dave Barach97d8dc22016-08-15 15:31:15 -0400762 /* decrement counter if dynamically learned mac */
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100763 if (!l2fib_entry_result_is_set_AGE_NOT (&result))
764 {
765 l2_bridge_domain_t *bd_config =
766 vec_elt_at_index (l2input_main.bd_configs, bd_index);
767 if (l2learn_main.global_learn_count)
768 l2learn_main.global_learn_count--;
769 if (bd_config->learn_count)
770 bd_config->learn_count--;
771 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700772
Dave Barach97d8dc22016-08-15 15:31:15 -0400773 /* Remove entry from hash table */
774 BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700775 return 0;
776}
777
Dave Barach97d8dc22016-08-15 15:31:15 -0400778/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400779 * Delete an entry from the L2FIB.
Dave Barach97d8dc22016-08-15 15:31:15 -0400780 * The CLI format is:
781 * l2fib del <mac> <bd-id>
782 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400784l2fib_del (vlib_main_t * vm,
785 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786{
Dave Barach97d8dc22016-08-15 15:31:15 -0400787 bd_main_t *bdm = &bd_main;
788 clib_error_t *error = 0;
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200789 u8 mac[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 u32 bd_id;
791 u32 bd_index;
Dave Barach97d8dc22016-08-15 15:31:15 -0400792 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700793
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200794 if (!unformat (input, "%U", unformat_ethernet_address, mac))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795 {
796 error = clib_error_return (0, "expected mac address `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400797 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798 goto done;
799 }
Dave Barach97d8dc22016-08-15 15:31:15 -0400800
801 if (!unformat (input, "%d", &bd_id))
802 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 error = clib_error_return (0, "expected bridge domain ID `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400804 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400806 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700807
808 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
Dave Barach97d8dc22016-08-15 15:31:15 -0400809 if (!p)
810 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700811 error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
812 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400813 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814 bd_index = p[0];
815
Dave Barach97d8dc22016-08-15 15:31:15 -0400816 /* Delete the entry */
John Lo7dbd7262018-05-31 10:25:18 -0400817 if (l2fib_del_entry (mac, bd_index, 0))
Dave Barach97d8dc22016-08-15 15:31:15 -0400818 {
819 error = clib_error_return (0, "mac entry not found");
820 goto done;
821 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822
Dave Barach97d8dc22016-08-15 15:31:15 -0400823done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824 return error;
825}
826
Billy McFall22aa3e92016-09-09 08:46:40 -0400827/*?
828 * This command deletes an existing MAC Address entry from the L2 FIB
829 * table of an existing bridge-domain.
830 *
831 * @cliexpar
832 * 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):
833 * @cliexcmd{l2fib del 52:54:00:53:18:33 200}
834?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400835/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700836VLIB_CLI_COMMAND (l2fib_del_cli, static) = {
837 .path = "l2fib del",
John Lo7dbd7262018-05-31 10:25:18 -0400838 .short_help = "l2fib del <mac> <bridge-domain-id> []",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 .function = l2fib_del,
840};
Dave Barach97d8dc22016-08-15 15:31:15 -0400841/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700842
Jerome Tollet0f8d1002021-01-07 12:44:17 +0100843static clib_error_t *
844l2fib_set_scan_delay (vlib_main_t *vm, unformat_input_t *input,
845 vlib_cli_command_t *cmd)
846{
847 clib_error_t *error = 0;
848 u32 scan_delay;
849 l2fib_main_t *fm = &l2fib_main;
850
851 if (!unformat (input, "%d", &scan_delay))
852 {
853 error = clib_error_return (0, "expecting delay but got `%U'",
854 format_unformat_error, input);
855 goto done;
856 }
857 fm->event_scan_delay = (f64) (scan_delay) *10e-3;
858 l2fib_flush_all_mac (vlib_get_main ());
859done:
860 return error;
861}
862
863/*?
864 * This command set scan delay (in 1/10s unit)
865 *
866?*/
867VLIB_CLI_COMMAND (l2fib_set_scan_delay_cli, static) = {
868 .path = "set l2fib scan-delay",
869 .short_help = "set l2fib scan-delay <delay>",
870 .function = l2fib_set_scan_delay,
871};
872
John Loda1f2c72017-03-24 20:11:15 -0400873/**
874 Kick off ager to scan MACs to age/delete MAC entries
875*/
876void
877l2fib_start_ager_scan (vlib_main_t * vm)
878{
Eyal Bari24db0ec2017-09-27 21:43:51 +0300879 uword evt = L2_MAC_AGE_PROCESS_EVENT_ONE_PASS;
John Loda1f2c72017-03-24 20:11:15 -0400880
881 /* check if there is at least one bd with mac aging enabled */
Eyal Bari24db0ec2017-09-27 21:43:51 +0300882 l2_bridge_domain_t *bd_config;
John Loda1f2c72017-03-24 20:11:15 -0400883 vec_foreach (bd_config, l2input_main.bd_configs)
Eyal Bari24db0ec2017-09-27 21:43:51 +0300884 {
John Loda1f2c72017-03-24 20:11:15 -0400885 if (bd_config->bd_id != ~0 && bd_config->mac_age != 0)
Eyal Bari24db0ec2017-09-27 21:43:51 +0300886 {
887 evt = L2_MAC_AGE_PROCESS_EVENT_START;
888 break;
889 }
890 }
John Loda1f2c72017-03-24 20:11:15 -0400891
892 vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index,
Eyal Bari24db0ec2017-09-27 21:43:51 +0300893 evt, 0);
John Loda1f2c72017-03-24 20:11:15 -0400894}
895
896/**
Eyal Bari7537e712017-04-27 14:07:55 +0300897 Flush all non static MACs from an interface
John Loda1f2c72017-03-24 20:11:15 -0400898*/
899void
900l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index)
901{
Neale Ranns47a3d992020-09-29 15:38:51 +0000902 l2_input_seq_num_inc (sw_if_index);
John Loda1f2c72017-03-24 20:11:15 -0400903 l2fib_start_ager_scan (vm);
904}
905
906/**
Eyal Bari7537e712017-04-27 14:07:55 +0300907 Flush all non static MACs in a bridge domain
John Loda1f2c72017-03-24 20:11:15 -0400908*/
909void
910l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index)
911{
Eyal Bari7537e712017-04-27 14:07:55 +0300912 l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
John Loda1f2c72017-03-24 20:11:15 -0400913 bd_config->seq_num += 1;
914 l2fib_start_ager_scan (vm);
915}
916
917/**
Eyal Bari7537e712017-04-27 14:07:55 +0300918 Flush all non static MACs - flushes all valid BDs
919*/
920void
921l2fib_flush_all_mac (vlib_main_t * vm)
922{
923 l2_bridge_domain_t *bd_config;
924 vec_foreach (bd_config, l2input_main.bd_configs)
925 if (bd_is_valid (bd_config))
926 bd_config->seq_num += 1;
927
928 l2fib_start_ager_scan (vm);
929}
930
931
932/**
John Loda1f2c72017-03-24 20:11:15 -0400933 Flush MACs, except static ones, associated with an interface
934 The CLI format is:
935 l2fib flush-mac interface <if-name>
936*/
937static clib_error_t *
938l2fib_flush_mac_int (vlib_main_t * vm,
939 unformat_input_t * input, vlib_cli_command_t * cmd)
940{
941 vnet_main_t *vnm = vnet_get_main ();
942 clib_error_t *error = 0;
943 u32 sw_if_index;
944
945 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
946 {
947 error = clib_error_return (0, "unknown interface `%U'",
948 format_unformat_error, input);
949 goto done;
950 }
951
952 l2fib_flush_int_mac (vm, sw_if_index);
953
954done:
955 return error;
956}
957
Eyal Bari7537e712017-04-27 14:07:55 +0300958/**
959 Flush all MACs, except static ones
960 The CLI format is:
961 l2fib flush-mac all
962*/
963static clib_error_t *
964l2fib_flush_mac_all (vlib_main_t * vm,
965 unformat_input_t * input, vlib_cli_command_t * cmd)
966{
967 l2fib_flush_all_mac (vm);
968 return 0;
969}
970
971/*?
972 * This command kick off ager to delete all existing MAC Address entries,
973 * except static ones, associated with an interface from the L2 FIB table.
974 *
975 * @cliexpar
976 * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
977 * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
978?*/
979/* *INDENT-OFF* */
980VLIB_CLI_COMMAND (l2fib_flush_mac_all_cli, static) = {
981 .path = "l2fib flush-mac all",
982 .short_help = "l2fib flush-mac all",
983 .function = l2fib_flush_mac_all,
984};
985/* *INDENT-ON* */
986
John Loda1f2c72017-03-24 20:11:15 -0400987/*?
988 * This command kick off ager to delete all existing MAC Address entries,
989 * except static ones, associated with an interface from the L2 FIB table.
990 *
991 * @cliexpar
992 * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
993 * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
994?*/
995/* *INDENT-OFF* */
996VLIB_CLI_COMMAND (l2fib_flush_mac_int_cli, static) = {
997 .path = "l2fib flush-mac interface",
998 .short_help = "l2fib flush-mac interface <if-name>",
999 .function = l2fib_flush_mac_int,
1000};
1001/* *INDENT-ON* */
1002
1003/**
1004 Flush bridge-domain MACs except static ones.
1005 The CLI format is:
1006 l2fib flush-mac bridge-domain <bd-id>
1007*/
1008static clib_error_t *
1009l2fib_flush_mac_bd (vlib_main_t * vm,
1010 unformat_input_t * input, vlib_cli_command_t * cmd)
1011{
1012 bd_main_t *bdm = &bd_main;
1013 clib_error_t *error = 0;
1014 u32 bd_index, bd_id;
1015 uword *p;
1016
1017 if (!unformat (input, "%d", &bd_id))
1018 {
1019 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
1020 format_unformat_error, input);
1021 goto done;
1022 }
1023
1024 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1025 if (p)
1026 bd_index = *p;
1027 else
1028 return clib_error_return (0, "No such bridge domain %d", bd_id);
1029
1030 l2fib_flush_bd_mac (vm, bd_index);
1031
1032done:
1033 return error;
1034}
1035
1036/*?
1037 * This command kick off ager to delete all existing MAC Address entries,
1038 * except static ones, in a bridge domain from the L2 FIB table.
1039 *
1040 * @cliexpar
1041 * Example of how to flush MAC Address entries learned in a bridge domain from the L2 FIB table:
1042 * @cliexcmd{l2fib flush-mac bridge-domain 1000}
1043?*/
1044/* *INDENT-OFF* */
1045VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = {
1046 .path = "l2fib flush-mac bridge-domain",
1047 .short_help = "l2fib flush-mac bridge-domain <bd-id>",
1048 .function = l2fib_flush_mac_bd,
1049};
1050/* *INDENT-ON* */
1051
Eyal Bariafc47aa2017-04-20 14:45:17 +03001052clib_error_t *
1053l2fib_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
1054{
1055 l2_input_config_t *config = l2input_intf_config (sw_if_index);
Neale Ranns47a3d992020-09-29 15:38:51 +00001056 if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0 &&
1057 l2_input_is_bridge (config))
Eyal Bariafc47aa2017-04-20 14:45:17 +03001058 l2fib_flush_int_mac (vnm->vlib_main, sw_if_index);
1059 return 0;
1060}
1061
1062VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2fib_sw_interface_up_down);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063
Dave Barach97d8dc22016-08-15 15:31:15 -04001064BVT (clib_bihash) * get_mac_table (void)
1065{
1066 l2fib_main_t *mp = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067 return &mp->mac_table;
1068}
1069
John Lo8d00fff2017-08-03 00:35:36 -04001070static_always_inline void *
1071allocate_mac_evt_buf (u32 client, u32 client_index)
1072{
1073 l2fib_main_t *fm = &l2fib_main;
1074 vl_api_l2_macs_event_t *mp = vl_msg_api_alloc
1075 (sizeof (*mp) + (fm->max_macs_in_event * sizeof (vl_api_mac_entry_t)));
Filip Tehlar5a9d2a12021-06-22 21:20:29 +00001076 mp->_vl_msg_id = htons (l2input_main.msg_id_base + VL_API_L2_MACS_EVENT);
John Lo8d00fff2017-08-03 00:35:36 -04001077 mp->pid = htonl (client);
1078 mp->client_index = client_index;
1079 return mp;
1080}
1081
1082static_always_inline f64
1083l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
1084{
1085 l2fib_main_t *fm = &l2fib_main;
1086 l2learn_main_t *lm = &l2learn_main;
1087
1088 BVT (clib_bihash) * h = &fm->mac_table;
1089 int i, j, k;
1090 f64 last_start = start_time;
1091 f64 accum_t = 0;
1092 f64 delta_t = 0;
1093 u32 evt_idx = 0;
1094 u32 learn_count = 0;
1095 u32 client = lm->client_pid;
1096 u32 cl_idx = lm->client_index;
1097 vl_api_l2_macs_event_t *mp = 0;
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001098 vl_api_registration_t *reg = 0;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001099 u32 bd_index;
1100 static u32 *bd_learn_counts = 0;
John Lo8d00fff2017-08-03 00:35:36 -04001101
Dave Barach32dcd3b2019-07-08 12:25:38 -04001102 /* Don't scan the l2 fib if it hasn't been instantiated yet */
1103 if (alloc_arena (h) == 0)
1104 return 0.0;
1105
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001106 vec_reset_length (bd_learn_counts);
1107 vec_validate (bd_learn_counts, vec_len (l2input_main.bd_configs) - 1);
1108
John Lo8d00fff2017-08-03 00:35:36 -04001109 if (client)
1110 {
1111 mp = allocate_mac_evt_buf (client, cl_idx);
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001112 reg = vl_api_client_index_to_registration (lm->client_index);
John Lo8d00fff2017-08-03 00:35:36 -04001113 }
1114
1115 for (i = 0; i < h->nbuckets; i++)
1116 {
1117 /* allow no more than 20us without a pause */
1118 delta_t = vlib_time_now (vm) - last_start;
1119 if (delta_t > 20e-6)
1120 {
1121 vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001122 /* in case a new bd was created while sleeping */
1123 vec_validate (bd_learn_counts,
1124 vec_len (l2input_main.bd_configs) - 1);
John Lo8d00fff2017-08-03 00:35:36 -04001125 last_start = vlib_time_now (vm);
1126 accum_t += delta_t;
1127 }
1128
1129 if (i < (h->nbuckets - 3))
1130 {
Dave Barach16e4a4a2020-04-16 12:00:14 -04001131 BVT (clib_bihash_bucket) * b =
1132 BV (clib_bihash_get_bucket) (h, i + 3);
Damjan Marionaf7fb042021-07-15 11:54:41 +02001133 clib_prefetch_load (b);
Dave Barach16e4a4a2020-04-16 12:00:14 -04001134 b = BV (clib_bihash_get_bucket) (h, i + 1);
1135 if (!BV (clib_bihash_bucket_is_empty) (b))
John Lo8d00fff2017-08-03 00:35:36 -04001136 {
1137 BVT (clib_bihash_value) * v =
1138 BV (clib_bihash_get_value) (h, b->offset);
Damjan Marionaf7fb042021-07-15 11:54:41 +02001139 clib_prefetch_load (v);
John Lo8d00fff2017-08-03 00:35:36 -04001140 }
1141 }
1142
Dave Barach16e4a4a2020-04-16 12:00:14 -04001143 BVT (clib_bihash_bucket) * b = BV (clib_bihash_get_bucket) (h, i);
1144 if (BV (clib_bihash_bucket_is_empty) (b))
John Lo8d00fff2017-08-03 00:35:36 -04001145 continue;
1146 BVT (clib_bihash_value) * v = BV (clib_bihash_get_value) (h, b->offset);
1147 for (j = 0; j < (1 << b->log2_pages); j++)
1148 {
1149 for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
1150 {
Dave Barachb9c8c572023-03-16 13:03:47 -04001151 if (BV (clib_bihash_is_free) (&v->kvp[k]))
John Lo8d00fff2017-08-03 00:35:36 -04001152 continue;
1153
1154 l2fib_entry_key_t key = {.raw = v->kvp[k].key };
1155 l2fib_entry_result_t result = {.raw = v->kvp[k].value };
1156
Neale Rannsb54d0812018-09-06 06:22:56 -07001157 if (!l2fib_entry_result_is_set_AGE_NOT (&result))
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001158 {
1159 learn_count++;
1160 vec_elt (bd_learn_counts, key.fields.bd_index)++;
1161 }
John Lo8d00fff2017-08-03 00:35:36 -04001162
John Lo8d00fff2017-08-03 00:35:36 -04001163 if (client)
1164 {
Eyal Bari24db0ec2017-09-27 21:43:51 +03001165 if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event))
1166 {
1167 /* event message full, send it and start a new one */
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001168 if (reg && vl_api_can_send_msg (reg))
Eyal Bari24db0ec2017-09-27 21:43:51 +03001169 {
1170 mp->n_macs = htonl (evt_idx);
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001171 vl_api_send_msg (reg, (u8 *) mp);
Eyal Bari24db0ec2017-09-27 21:43:51 +03001172 mp = allocate_mac_evt_buf (client, cl_idx);
1173 }
1174 else
1175 {
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001176 if (reg)
Dave Barach59b25652017-09-10 15:04:27 -04001177 clib_warning ("MAC event to pid %d queue stuffed!"
1178 " %d MAC entries lost", client,
1179 evt_idx);
Eyal Bari24db0ec2017-09-27 21:43:51 +03001180 }
1181 evt_idx = 0;
1182 }
1183
Neale Rannsb54d0812018-09-06 06:22:56 -07001184 if (l2fib_entry_result_is_set_LRN_EVT (&result))
John Lo8d00fff2017-08-03 00:35:36 -04001185 {
1186 /* copy mac entry to event msg */
Dave Barach178cf492018-11-13 16:34:13 -05001187 clib_memcpy_fast (mp->mac[evt_idx].mac_addr,
1188 key.fields.mac, 6);
Neale Rannsb54d0812018-09-06 06:22:56 -07001189 mp->mac[evt_idx].action =
1190 l2fib_entry_result_is_set_LRN_MOV (&result) ?
Jakub Grajciar145e3302019-10-24 13:52:42 +02001191 (vl_api_mac_event_action_t) MAC_EVENT_ACTION_MOVE
1192 : (vl_api_mac_event_action_t) MAC_EVENT_ACTION_ADD;
1193 mp->mac[evt_idx].action =
1194 htonl (mp->mac[evt_idx].action);
John Lo8d00fff2017-08-03 00:35:36 -04001195 mp->mac[evt_idx].sw_if_index =
1196 htonl (result.fields.sw_if_index);
John Loe23c99e2018-03-13 21:53:18 -04001197 /* clear event bits and update mac entry */
Neale Rannsb54d0812018-09-06 06:22:56 -07001198 l2fib_entry_result_clear_LRN_EVT (&result);
1199 l2fib_entry_result_clear_LRN_MOV (&result);
John Lo8d00fff2017-08-03 00:35:36 -04001200 BVT (clib_bihash_kv) kv;
1201 kv.key = key.raw;
1202 kv.value = result.raw;
1203 BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1);
1204 evt_idx++;
1205 continue; /* skip aging */
1206 }
1207 }
1208
Neale Rannsb54d0812018-09-06 06:22:56 -07001209 if (event_only || l2fib_entry_result_is_set_AGE_NOT (&result))
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -07001210 continue; /* skip aging - static_mac always age_not */
John Lo8d00fff2017-08-03 00:35:36 -04001211
1212 /* start aging processing */
1213 u32 bd_index = key.fields.bd_index;
1214 u32 sw_if_index = result.fields.sw_if_index;
Neale Ranns47a3d992020-09-29 15:38:51 +00001215 u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index);
1216 if (result.fields.sn != sn)
John Lo8d00fff2017-08-03 00:35:36 -04001217 goto age_out; /* stale mac */
1218
1219 l2_bridge_domain_t *bd_config =
1220 vec_elt_at_index (l2input_main.bd_configs, bd_index);
1221
1222 if (bd_config->mac_age == 0)
1223 continue; /* skip aging */
1224
1225 i16 delta = (u8) (start_time / 60) - result.fields.timestamp;
1226 delta += delta < 0 ? 256 : 0;
1227
1228 if (delta < bd_config->mac_age)
1229 continue; /* still valid */
1230
1231 age_out:
1232 if (client)
1233 {
1234 /* copy mac entry to event msg */
Dave Barach178cf492018-11-13 16:34:13 -05001235 clib_memcpy_fast (mp->mac[evt_idx].mac_addr, key.fields.mac,
1236 6);
Jakub Grajciar145e3302019-10-24 13:52:42 +02001237 mp->mac[evt_idx].action =
1238 (vl_api_mac_event_action_t) MAC_EVENT_ACTION_DELETE;
1239 mp->mac[evt_idx].action = htonl (mp->mac[evt_idx].action);
John Lo8d00fff2017-08-03 00:35:36 -04001240 mp->mac[evt_idx].sw_if_index =
1241 htonl (result.fields.sw_if_index);
1242 evt_idx++;
1243 }
1244 /* delete mac entry */
1245 BVT (clib_bihash_kv) kv;
1246 kv.key = key.raw;
1247 BV (clib_bihash_add_del) (&fm->mac_table, &kv, 0);
1248 learn_count--;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001249 vec_elt (bd_learn_counts, key.fields.bd_index)--;
Dave Barach28374ca2018-08-07 12:46:18 -04001250 /*
1251 * Note: we may have just freed the bucket's backing
1252 * storage, so check right here...
1253 */
Dave Barach16e4a4a2020-04-16 12:00:14 -04001254 if (BV (clib_bihash_bucket_is_empty) (b))
Dave Barach28374ca2018-08-07 12:46:18 -04001255 goto doublebreak;
John Lo8d00fff2017-08-03 00:35:36 -04001256 }
1257 v++;
1258 }
Dave Barach28374ca2018-08-07 12:46:18 -04001259 doublebreak:
1260 ;
John Lo8d00fff2017-08-03 00:35:36 -04001261 }
1262
1263 /* keep learn count consistent */
1264 l2learn_main.global_learn_count = learn_count;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001265 vec_foreach_index (bd_index, l2input_main.bd_configs)
1266 {
1267 vec_elt (l2input_main.bd_configs, bd_index).learn_count =
1268 vec_elt (bd_learn_counts, bd_index);
1269 }
John Lo8d00fff2017-08-03 00:35:36 -04001270
1271 if (mp)
1272 {
1273 /* send any outstanding mac event message else free message buffer */
1274 if (evt_idx)
1275 {
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001276 if (reg && vl_api_can_send_msg (reg))
John Lo8d00fff2017-08-03 00:35:36 -04001277 {
1278 mp->n_macs = htonl (evt_idx);
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001279 vl_api_send_msg (reg, (u8 *) mp);
John Lo8d00fff2017-08-03 00:35:36 -04001280 }
1281 else
1282 {
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001283 if (reg)
Dave Barach59b25652017-09-10 15:04:27 -04001284 clib_warning ("MAC event to pid %d queue stuffed!"
1285 " %d MAC entries lost", client, evt_idx);
John Lo8d00fff2017-08-03 00:35:36 -04001286 vl_msg_api_free (mp);
1287 }
1288 }
1289 else
1290 vl_msg_api_free (mp);
1291 }
1292 return delta_t + accum_t;
1293}
1294
Damjan Mariond171d482016-12-05 14:16:38 +01001295static uword
1296l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
1297 vlib_frame_t * f)
1298{
1299 uword event_type, *event_data = 0;
John Lo8d00fff2017-08-03 00:35:36 -04001300 l2fib_main_t *fm = &l2fib_main;
1301 l2learn_main_t *lm = &l2learn_main;
Damjan Mariond171d482016-12-05 14:16:38 +01001302 bool enabled = 0;
John Lo7f358b32018-04-28 01:19:24 -04001303 f64 start_time, next_age_scan_time = CLIB_TIME_MAX;
Damjan Mariond171d482016-12-05 14:16:38 +01001304
1305 while (1)
1306 {
Eyal Bari24db0ec2017-09-27 21:43:51 +03001307 if (lm->client_pid)
1308 vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay);
1309 else if (enabled)
John Lo8d00fff2017-08-03 00:35:36 -04001310 {
Eyal Bari24db0ec2017-09-27 21:43:51 +03001311 f64 t = next_age_scan_time - vlib_time_now (vm);
1312 vlib_process_wait_for_event_or_clock (vm, t);
John Lo8d00fff2017-08-03 00:35:36 -04001313 }
Damjan Mariond171d482016-12-05 14:16:38 +01001314 else
1315 vlib_process_wait_for_event (vm);
1316
1317 event_type = vlib_process_get_events (vm, &event_data);
1318 vec_reset_length (event_data);
1319
John Lo8d00fff2017-08-03 00:35:36 -04001320 start_time = vlib_time_now (vm);
Eyal Bari24db0ec2017-09-27 21:43:51 +03001321 enum
1322 { SCAN_MAC_AGE, SCAN_MAC_EVENT, SCAN_DISABLE } scan = SCAN_MAC_AGE;
John Lo8d00fff2017-08-03 00:35:36 -04001323
Damjan Mariond171d482016-12-05 14:16:38 +01001324 switch (event_type)
1325 {
John Lo8d00fff2017-08-03 00:35:36 -04001326 case ~0: /* timer expired */
Eyal Bari24db0ec2017-09-27 21:43:51 +03001327 if (lm->client_pid != 0 && start_time < next_age_scan_time)
John Lo8d00fff2017-08-03 00:35:36 -04001328 scan = SCAN_MAC_EVENT;
Damjan Mariond171d482016-12-05 14:16:38 +01001329 break;
John Lo8d00fff2017-08-03 00:35:36 -04001330
Damjan Mariond171d482016-12-05 14:16:38 +01001331 case L2_MAC_AGE_PROCESS_EVENT_START:
1332 enabled = 1;
1333 break;
John Lo8d00fff2017-08-03 00:35:36 -04001334
Damjan Mariond171d482016-12-05 14:16:38 +01001335 case L2_MAC_AGE_PROCESS_EVENT_STOP:
1336 enabled = 0;
Eyal Bari24db0ec2017-09-27 21:43:51 +03001337 scan = SCAN_DISABLE;
1338 break;
John Lo8d00fff2017-08-03 00:35:36 -04001339
John Loda1f2c72017-03-24 20:11:15 -04001340 case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS:
John Loda1f2c72017-03-24 20:11:15 -04001341 break;
John Lo8d00fff2017-08-03 00:35:36 -04001342
Damjan Mariond171d482016-12-05 14:16:38 +01001343 default:
1344 ASSERT (0);
1345 }
Eyal Bari7537e712017-04-27 14:07:55 +03001346
John Lo8d00fff2017-08-03 00:35:36 -04001347 if (scan == SCAN_MAC_EVENT)
1348 l2fib_main.evt_scan_duration = l2fib_scan (vm, start_time, 1);
1349 else
Eyal Bari24db0ec2017-09-27 21:43:51 +03001350 {
1351 if (scan == SCAN_MAC_AGE)
1352 l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0);
1353 if (scan == SCAN_DISABLE)
1354 {
1355 l2fib_main.age_scan_duration = 0;
1356 l2fib_main.evt_scan_duration = 0;
1357 }
1358 /* schedule next scan */
1359 if (enabled)
1360 next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL;
1361 else
John Lo7f358b32018-04-28 01:19:24 -04001362 next_age_scan_time = CLIB_TIME_MAX;
Eyal Bari24db0ec2017-09-27 21:43:51 +03001363 }
Damjan Mariond171d482016-12-05 14:16:38 +01001364 }
1365 return 0;
1366}
1367
1368/* *INDENT-OFF* */
1369VLIB_REGISTER_NODE (l2fib_mac_age_scanner_process_node) = {
1370 .function = l2fib_mac_age_scanner_process,
1371 .type = VLIB_NODE_TYPE_PROCESS,
1372 .name = "l2fib-mac-age-scanner-process",
1373};
1374/* *INDENT-ON* */
1375
Dave Barach97d8dc22016-08-15 15:31:15 -04001376clib_error_t *
1377l2fib_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001378{
Dave Barach97d8dc22016-08-15 15:31:15 -04001379 l2fib_main_t *mp = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380 l2fib_entry_key_t test_key;
1381 u8 test_mac[6];
Dave Barach97d8dc22016-08-15 15:31:15 -04001382
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383 mp->vlib_main = vm;
Dave Barach97d8dc22016-08-15 15:31:15 -04001384 mp->vnet_main = vnet_get_main ();
Damjan Marion95147812020-09-14 12:18:44 +02001385 if (mp->mac_table_n_buckets == 0)
1386 mp->mac_table_n_buckets = L2FIB_NUM_BUCKETS;
1387 if (mp->mac_table_memory_size == 0)
1388 mp->mac_table_memory_size = L2FIB_MEMORY_SIZE;
1389 mp->mac_table_initialized = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001390
Dave Barach97d8dc22016-08-15 15:31:15 -04001391 /* verify the key constructor is good, since it is endian-sensitive */
Dave Barachb7b92992018-10-17 10:38:51 -04001392 clib_memset (test_mac, 0, sizeof (test_mac));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393 test_mac[0] = 0x11;
1394 test_key.raw = 0;
Dave Barach97d8dc22016-08-15 15:31:15 -04001395 test_key.raw = l2fib_make_key ((u8 *) & test_mac, 0x1234);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001396 ASSERT (test_key.fields.mac[0] == 0x11);
1397 ASSERT (test_key.fields.bd_index == 0x1234);
1398
1399 return 0;
1400}
1401
1402VLIB_INIT_FUNCTION (l2fib_init);
1403
Damjan Marion95147812020-09-14 12:18:44 +02001404static clib_error_t *
1405lfib_config (vlib_main_t * vm, unformat_input_t * input)
1406{
1407 l2fib_main_t *lm = &l2fib_main;
1408 uword table_size = ~0;
1409 u32 n_buckets = ~0;
1410
1411 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1412 {
1413 if (unformat (input, "table-size %U", unformat_memory_size,
1414 &table_size))
1415 ;
1416 else if (unformat (input, "num-buckets %u", &n_buckets))
1417 ;
1418 else
1419 return clib_error_return (0, "unknown input `%U'",
1420 format_unformat_error, input);
1421 }
1422
1423 if (n_buckets != ~0)
1424 {
1425 if (!is_pow2 (n_buckets))
1426 return clib_error_return (0, "num-buckets must be power of 2");
1427 lm->mac_table_n_buckets = n_buckets;
1428 }
1429
1430 if (table_size != ~0)
1431 lm->mac_table_memory_size = table_size;
1432 return 0;
1433}
1434
1435VLIB_CONFIG_FUNCTION (lfib_config, "l2fib");
1436
Dave Barach97d8dc22016-08-15 15:31:15 -04001437/*
1438 * fd.io coding-style-patch-verification: ON
1439 *
1440 * Local Variables:
1441 * eval: (c-set-style "gnu")
1442 * End:
1443 */