blob: ad301af78f44690ce45d5cbefee52b38479a8348 [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
98 return format (s, "%U", format_vnet_sw_interface_name, vnm,
Dave Barach3940de32019-07-23 16:28:36 -040099 vnet_get_sw_interface_or_null (vnm, sw_if_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100}
101
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700102typedef struct l2fib_dump_walk_ctx_t_
103{
104 u32 bd_index;
105 l2fib_entry_key_t *l2fe_key;
106 l2fib_entry_result_t *l2fe_res;
107} l2fib_dump_walk_ctx_t;
108
Neale Rannsf50bac12019-12-06 05:53:17 +0000109static int
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700110l2fib_dump_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
111{
112 l2fib_dump_walk_ctx_t *ctx = arg;
113 l2fib_entry_result_t result;
114 l2fib_entry_key_t key;
115
116 key.raw = kvp->key;
117 result.raw = kvp->value;
118
119 if ((ctx->bd_index == ~0) || (ctx->bd_index == key.fields.bd_index))
120 {
121 vec_add1 (ctx->l2fe_key, key);
122 vec_add1 (ctx->l2fe_res, result);
123 }
Neale Rannsf50bac12019-12-06 05:53:17 +0000124
125 return (BIHASH_WALK_CONTINUE);
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700126}
127
Dave Barach97d8dc22016-08-15 15:31:15 -0400128void
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700129l2fib_table_dump (u32 bd_index,
130 l2fib_entry_key_t ** l2fe_key,
Dave Barach97d8dc22016-08-15 15:31:15 -0400131 l2fib_entry_result_t ** l2fe_res)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132{
Dave Barach97d8dc22016-08-15 15:31:15 -0400133 l2fib_main_t *msm = &l2fib_main;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700134 l2fib_dump_walk_ctx_t ctx = {
135 .bd_index = bd_index,
136 };
137
138 BV (clib_bihash_foreach_key_value_pair)
139 (&msm->mac_table, l2fib_dump_walk_cb, &ctx);
140
141 *l2fe_key = ctx.l2fe_key;
142 *l2fe_res = ctx.l2fe_res;
143}
144
Neale Ranns47a3d992020-09-29 15:38:51 +0000145void
146l2_fib_extract_seq_num (l2fib_seq_num_t sn, u8 * bd_sn, u8 * if_sn)
147{
148 *bd_sn = sn >> 8;
149 *if_sn = sn & 0xff;
150}
151
152u8 *
153format_l2_fib_seq_num (u8 * s, va_list * a)
154{
155 l2fib_seq_num_t sn = va_arg (*a, int);
156 u8 bd_sn, if_sn;
157
158 l2_fib_extract_seq_num (sn, &bd_sn, &if_sn);
159
160 s = format (s, "%3d/%-3d", bd_sn, if_sn);
161
162 return (s);
163}
164
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700165typedef struct l2fib_show_walk_ctx_t_
166{
167 u8 first_entry;
168 u8 verbose;
169 vlib_main_t *vm;
170 vnet_main_t *vnm;
171 u32 total_entries;
172 u32 bd_index;
173 u8 learn;
174 u8 add;
175 u8 now;
176} l2fib_show_walk_ctx_t;
177
Neale Rannsf50bac12019-12-06 05:53:17 +0000178static int
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700179l2fib_show_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
180{
181 l2fib_show_walk_ctx_t *ctx = arg;
182 l2_bridge_domain_t *bd_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 l2fib_entry_result_t result;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700184 l2fib_entry_key_t key;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700186 if (ctx->verbose && ctx->first_entry)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700188 ctx->first_entry = 0;
189 vlib_cli_output (ctx->vm,
190 "%=19s%=7s%=7s%=8s%=9s%=7s%=7s%=5s%=30s",
191 "Mac-Address", "BD-Idx", "If-Idx",
192 "BSN-ISN", "Age(min)", "static", "filter",
193 "bvi", "Interface-Name");
194 }
195
196 key.raw = kvp->key;
197 result.raw = kvp->value;
198 ctx->total_entries++;
199
200 if (ctx->verbose &&
201 ((ctx->bd_index >> 31) || (ctx->bd_index == key.fields.bd_index)))
202 {
203 u8 *s = NULL;
204
Neale Rannsb54d0812018-09-06 06:22:56 -0700205 if (ctx->learn && l2fib_entry_result_is_set_AGE_NOT (&result))
Neale Rannsf50bac12019-12-06 05:53:17 +0000206 return (BIHASH_WALK_CONTINUE); /* skip provisioned macs */
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700207
Neale Rannsb54d0812018-09-06 06:22:56 -0700208 if (ctx->add && !l2fib_entry_result_is_set_AGE_NOT (&result))
Neale Rannsf50bac12019-12-06 05:53:17 +0000209 return (BIHASH_WALK_CONTINUE); /* skip learned macs */
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700210
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100211 bd_config = &vec_elt (l2input_main.bd_configs, key.fields.bd_index);
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700212
Neale Rannsb54d0812018-09-06 06:22:56 -0700213 if (l2fib_entry_result_is_set_AGE_NOT (&result))
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700214 s = format (s, "no");
215 else if (bd_config->mac_age == 0)
216 s = format (s, "-");
217 else
Dave Barach97d8dc22016-08-15 15:31:15 -0400218 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700219 i16 delta = ctx->now - result.fields.timestamp;
220 delta += delta < 0 ? 256 : 0;
221 s = format (s, "%d", delta);
Dave Barach97d8dc22016-08-15 15:31:15 -0400222 }
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700223
224 vlib_cli_output (ctx->vm,
Neale Ranns47a3d992020-09-29 15:38:51 +0000225 "%=19U%=7d%=7d %U%=9v%=7s%=7s%=5s%=30U",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700226 format_ethernet_address, key.fields.mac,
227 key.fields.bd_index,
228 result.fields.sw_if_index == ~0
229 ? -1 : result.fields.sw_if_index,
Neale Ranns47a3d992020-09-29 15:38:51 +0000230 format_l2_fib_seq_num, result.fields.sn, s,
Neale Rannsb54d0812018-09-06 06:22:56 -0700231 l2fib_entry_result_is_set_STATIC (&result) ? "*" : "-",
232 l2fib_entry_result_is_set_FILTER (&result) ? "*" : "-",
233 l2fib_entry_result_is_set_BVI (&result) ? "*" : "-",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700234 format_vnet_sw_if_index_name_with_NA,
235 ctx->vnm, result.fields.sw_if_index);
236 vec_free (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 }
Neale Rannsf50bac12019-12-06 05:53:17 +0000238
239 return (BIHASH_WALK_CONTINUE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240}
241
Chris Luke16bcf7d2016-09-01 14:31:46 -0400242/** Display the contents of the l2fib. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400244show_l2fib (vlib_main_t * vm,
245 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246{
Dave Barach97d8dc22016-08-15 15:31:15 -0400247 bd_main_t *bdm = &bd_main;
248 l2fib_main_t *msm = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 u8 raw = 0;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700250 u32 bd_id;
251 l2fib_show_walk_ctx_t ctx = {
252 .first_entry = 1,
253 .bd_index = ~0,
254 .now = (u8) (vlib_time_now (vm) / 60),
255 .vm = vm,
256 .vnm = msm->vnet_main,
257 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258
John Lo7dbd7262018-05-31 10:25:18 -0400259 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
John Lo8d00fff2017-08-03 00:35:36 -0400260 {
John Lo7dbd7262018-05-31 10:25:18 -0400261 if (unformat (input, "raw"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400262 {
John Lo7dbd7262018-05-31 10:25:18 -0400263 raw = 1;
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700264 ctx.verbose = 0;
John Lo7dbd7262018-05-31 10:25:18 -0400265 break;
266 }
267 else if (unformat (input, "verbose"))
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700268 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400269 else if (unformat (input, "all"))
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700270 ctx.verbose = 1;
271 else if (unformat (input, "bd_index %d", &ctx.bd_index))
272 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400273 else if (unformat (input, "learn"))
274 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700275 ctx.add = 0;
276 ctx.learn = 1;
277 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400278 }
279 else if (unformat (input, "add"))
280 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700281 ctx.learn = 0;
282 ctx.add = 1;
283 ctx.verbose = 1;
John Lo7dbd7262018-05-31 10:25:18 -0400284 }
285 else if (unformat (input, "bd_id %d", &bd_id))
286 {
287 uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
288 if (p)
289 {
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700290 ctx.verbose = 1;
291 ctx.bd_index = p[0];
John Lo7dbd7262018-05-31 10:25:18 -0400292 }
293 else
294 return clib_error_return (0,
295 "bridge domain id %d doesn't exist\n",
296 bd_id);
Dave Barach97d8dc22016-08-15 15:31:15 -0400297 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 else
John Lo7dbd7262018-05-31 10:25:18 -0400299 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300 }
301
Damjan Marion95147812020-09-14 12:18:44 +0200302 if (msm->mac_table_initialized == 0)
303 {
304 vlib_cli_output (vm, "no l2fib entries");
305 return 0;
306 }
307
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700308 BV (clib_bihash_foreach_key_value_pair)
309 (&msm->mac_table, l2fib_show_walk_cb, &ctx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700311 if (ctx.total_entries == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312 vlib_cli_output (vm, "no l2fib entries");
313 else
John Lo8d00fff2017-08-03 00:35:36 -0400314 {
315 l2learn_main_t *lm = &l2learn_main;
316 vlib_cli_output (vm, "L2FIB total/learned entries: %d/%d "
317 "Last scan time: %.4esec Learn limit: %d ",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700318 ctx.total_entries, lm->global_learn_count,
John Lo8d00fff2017-08-03 00:35:36 -0400319 msm->age_scan_duration, lm->global_learn_limit);
320 if (lm->client_pid)
321 vlib_cli_output (vm, "L2MAC events client PID: %d "
322 "Last e-scan time: %.4esec Delay: %.2esec "
323 "Max macs in event: %d",
324 lm->client_pid, msm->evt_scan_duration,
325 msm->event_scan_delay, msm->max_macs_in_event);
326 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327
328 if (raw)
329 vlib_cli_output (vm, "Raw Hash Table:\n%U\n",
Neale Ranns99a3c6c2018-08-07 02:54:31 -0700330 BV (format_bihash), &msm->mac_table, 1 /* verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700331
332 return 0;
333}
334
Billy McFall22aa3e92016-09-09 08:46:40 -0400335/*?
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -0700336 * This command displays the MAC Address entries of the L2 FIB table.
Billy McFall22aa3e92016-09-09 08:46:40 -0400337 * Output can be filtered to just get the number of MAC Addresses or display
338 * each MAC Address for all bridge domains or just a single bridge domain.
339 *
340 * @cliexpar
341 * Example of how to display the number of MAC Address entries in the L2
342 * FIB table:
343 * @cliexstart{show l2fib}
344 * 3 l2fib entries
345 * @cliexend
346 * Example of how to display all the MAC Address entries in the L2
347 * FIB table:
John Lo7dbd7262018-05-31 10:25:18 -0400348 * @cliexstart{show l2fib all}
Billy McFall22aa3e92016-09-09 08:46:40 -0400349 * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
350 * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
351 * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
352 * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
353 * 3 l2fib entries
354 * @cliexend
355?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400356/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357VLIB_CLI_COMMAND (show_l2fib_cli, static) = {
358 .path = "show l2fib",
John Lo7dbd7262018-05-31 10:25:18 -0400359 .short_help = "show l2fib [all] | [bd_id <nn> | bd_index <nn>] [learn | add] | [raw]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 .function = show_l2fib,
361};
Dave Barach97d8dc22016-08-15 15:31:15 -0400362/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363
Damjan Marion95147812020-09-14 12:18:44 +0200364void
365l2fib_table_init (void)
366{
367 l2fib_main_t *mp = &l2fib_main;
368
369 if (mp->mac_table_initialized == 1)
370 return;
371
372 BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table",
373 mp->mac_table_n_buckets, mp->mac_table_memory_size);
374 mp->mac_table_initialized = 1;
375}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376
Dave Barach97d8dc22016-08-15 15:31:15 -0400377/* Remove all entries from the l2fib */
378void
Eyal Bari7537e712017-04-27 14:07:55 +0300379l2fib_clear_table (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380{
Dave Barach97d8dc22016-08-15 15:31:15 -0400381 l2fib_main_t *mp = &l2fib_main;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100382 l2_bridge_domain_t *bd_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383
Damjan Marion95147812020-09-14 12:18:44 +0200384 if (mp->mac_table_initialized == 0)
385 return;
386
Matthew Smith3a97a452020-10-12 15:04:39 -0500387 mp->mac_table_initialized = 0;
388
Eyal Bari7537e712017-04-27 14:07:55 +0300389 /* Remove all entries */
390 BV (clib_bihash_free) (&mp->mac_table);
Damjan Marion95147812020-09-14 12:18:44 +0200391 l2fib_table_init ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392 l2learn_main.global_learn_count = 0;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100393 vec_foreach (bd_config, l2input_main.bd_configs)
394 bd_config->learn_count = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395}
396
Chris Luke16bcf7d2016-09-01 14:31:46 -0400397/** Clear all entries in L2FIB.
398 * @TODO: Later we may want a way to remove only the non-static entries
Dave Barach97d8dc22016-08-15 15:31:15 -0400399 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400401clear_l2fib (vlib_main_t * vm,
402 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403{
Eyal Bari7537e712017-04-27 14:07:55 +0300404 l2fib_clear_table ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405 return 0;
406}
407
Billy McFall22aa3e92016-09-09 08:46:40 -0400408/*?
409 * This command clears all the MAC Address entries from the L2 FIB table.
410 *
411 * @cliexpar
412 * Example of how to clear the L2 FIB Table:
413 * @cliexcmd{clear l2fib}
414 * Example to show the L2 FIB Table has been cleared:
415 * @cliexstart{show l2fib verbose}
416 * no l2fib entries
417 * @cliexend
418?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400419/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420VLIB_CLI_COMMAND (clear_l2fib_cli, static) = {
421 .path = "clear l2fib",
Billy McFall22aa3e92016-09-09 08:46:40 -0400422 .short_help = "clear l2fib",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423 .function = clear_l2fib,
424};
Dave Barach97d8dc22016-08-15 15:31:15 -0400425/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426
Neale Ranns47a3d992020-09-29 15:38:51 +0000427static l2fib_seq_num_t
Eyal Bari7537e712017-04-27 14:07:55 +0300428l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index)
429{
Eyal Bari7537e712017-04-27 14:07:55 +0300430 l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
Neale Ranns47a3d992020-09-29 15:38:51 +0000431
432 return l2_fib_mk_seq_num (bd_config->seq_num,
433 l2_input_seq_num (sw_if_index));
Eyal Bari7537e712017-04-27 14:07:55 +0300434}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435
Dave Barach97d8dc22016-08-15 15:31:15 -0400436/**
437 * Add an entry to the l2fib.
438 * If the entry already exists then overwrite it
439 */
440void
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700441l2fib_add_entry (const u8 * mac, u32 bd_index,
Neale Rannsb54d0812018-09-06 06:22:56 -0700442 u32 sw_if_index, l2fib_entry_result_flags_t flags)
Dave Barach97d8dc22016-08-15 15:31:15 -0400443{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444 l2fib_entry_key_t key;
445 l2fib_entry_result_t result;
Dave Barach97d8dc22016-08-15 15:31:15 -0400446 __attribute__ ((unused)) u32 bucket_contents;
John Lo8d00fff2017-08-03 00:35:36 -0400447 l2fib_main_t *fm = &l2fib_main;
448 l2learn_main_t *lm = &l2learn_main;
Dave Barach97d8dc22016-08-15 15:31:15 -0400449 BVT (clib_bihash_kv) kv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450
Damjan Marion95147812020-09-14 12:18:44 +0200451 if (fm->mac_table_initialized == 0)
452 l2fib_table_init ();
453
Dave Barach97d8dc22016-08-15 15:31:15 -0400454 /* set up key */
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200455 key.raw = l2fib_make_key (mac, bd_index);
John Lob2e73b12020-01-07 16:35:29 -0500456 kv.key = key.raw;
Dave Barach97d8dc22016-08-15 15:31:15 -0400457
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -0700458 /* check if entry already exist */
John Lo8d00fff2017-08-03 00:35:36 -0400459 if (BV (clib_bihash_search) (&fm->mac_table, &kv, &kv))
460 {
461 /* decrement counter if overwriting a learned mac */
462 result.raw = kv.value;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100463 if (!l2fib_entry_result_is_set_AGE_NOT (&result))
464 {
465 l2_bridge_domain_t *bd_config =
466 vec_elt_at_index (l2input_main.bd_configs, bd_index);
467
468 /* check if learn_count == 0 in case of race condition between 2
469 * workers adding an entry simultaneously */
470 /* learn_count variable may have little inaccuracy because they are
471 * not incremented/decremented with atomic operations */
472 /* l2fib_scan is call every 2sec fixing potential inaccuracy */
473 if (lm->global_learn_count)
474 lm->global_learn_count--;
475 if (bd_config->learn_count)
476 bd_config->learn_count--;
477 }
John Lo8d00fff2017-08-03 00:35:36 -0400478 }
479
Dave Barach97d8dc22016-08-15 15:31:15 -0400480 /* set up result */
481 result.raw = 0; /* clear all fields */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700482 result.fields.sw_if_index = sw_if_index;
Neale Rannsb54d0812018-09-06 06:22:56 -0700483 result.fields.flags = flags;
484
485 /* no aging for provisioned entry */
486 l2fib_entry_result_set_AGE_NOT (&result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488 kv.value = result.raw;
489
John Lo8d00fff2017-08-03 00:35:36 -0400490 BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1 /* is_add */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491}
492
Dave Barach97d8dc22016-08-15 15:31:15 -0400493/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400494 * Add an entry to the L2FIB.
Dave Barach97d8dc22016-08-15 15:31:15 -0400495 * The CLI format is:
496 * l2fib add <mac> <bd> <intf> [static] [bvi]
497 * l2fib add <mac> <bd> filter
498 * Note that filter and bvi entries are always static
499 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400501l2fib_add (vlib_main_t * vm,
502 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503{
Dave Barach97d8dc22016-08-15 15:31:15 -0400504 bd_main_t *bdm = &bd_main;
505 vnet_main_t *vnm = vnet_get_main ();
506 clib_error_t *error = 0;
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200507 u8 mac[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 u32 bd_id;
509 u32 bd_index;
510 u32 sw_if_index = ~0;
Dave Barach97d8dc22016-08-15 15:31:15 -0400511 uword *p;
Neale Rannsb54d0812018-09-06 06:22:56 -0700512 l2fib_entry_result_flags_t flags;
513
514 flags = L2FIB_ENTRY_RESULT_FLAG_NONE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200516 if (!unformat (input, "%U", unformat_ethernet_address, mac))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517 {
518 error = clib_error_return (0, "expected mac address `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400519 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520 goto done;
521 }
Dave Barach97d8dc22016-08-15 15:31:15 -0400522
523 if (!unformat (input, "%d", &bd_id))
524 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 error = clib_error_return (0, "expected bridge domain ID `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400526 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400528 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529
530 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
Dave Barach97d8dc22016-08-15 15:31:15 -0400531 if (!p)
532 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533 error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
534 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400535 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 bd_index = p[0];
537
Dave Barach97d8dc22016-08-15 15:31:15 -0400538 if (unformat (input, "filter"))
539 {
John Lo14edd972017-10-31 13:26:02 -0400540 l2fib_add_filter_entry (mac, bd_index);
541 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543
John Lo14edd972017-10-31 13:26:02 -0400544 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
545 {
546 error = clib_error_return (0, "unknown interface `%U'",
547 format_unformat_error, input);
548 goto done;
549 }
550
551 if (unformat (input, "static"))
Neale Rannsb54d0812018-09-06 06:22:56 -0700552 flags |= L2FIB_ENTRY_RESULT_FLAG_STATIC;
John Lo14edd972017-10-31 13:26:02 -0400553 else if (unformat (input, "bvi"))
Neale Rannsb54d0812018-09-06 06:22:56 -0700554 flags |= (L2FIB_ENTRY_RESULT_FLAG_STATIC | L2FIB_ENTRY_RESULT_FLAG_BVI);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555
John Lob2fd6cb2017-07-12 19:56:45 -0400556 if (vec_len (l2input_main.configs) <= sw_if_index)
557 {
558 error = clib_error_return (0, "Interface sw_if_index %d not in L2 mode",
559 sw_if_index);
560 goto done;
561 }
562
Neale Rannsb54d0812018-09-06 06:22:56 -0700563 l2fib_add_entry (mac, bd_index, sw_if_index, flags);
Dave Barach97d8dc22016-08-15 15:31:15 -0400564
565done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566 return error;
567}
568
Billy McFall22aa3e92016-09-09 08:46:40 -0400569/*?
570 * This command adds a MAC Address entry to the L2 FIB table
571 * of an existing bridge-domain. The MAC Address can be static
572 * or dynamic. This command also allows a filter to be added,
573 * such that packets with given MAC Addresses (source mac or
574 * destination mac match) are dropped.
575 *
576 * @cliexpar
577 * Example of how to add a dynamic MAC Address entry to the L2 FIB table
578 * of a bridge-domain (where 200 is the bridge-domain-id):
579 * @cliexcmd{l2fib add 52:54:00:53:18:33 200 GigabitEthernet0/8/0.200}
580 * Example of how to add a static MAC Address entry to the L2 FIB table
581 * of a bridge-domain (where 200 is the bridge-domain-id):
582 * @cliexcmd{l2fib add 52:54:00:53:18:55 200 GigabitEthernet0/8/0.200 static}
583 * Example of how to add a filter such that a packet with the given MAC
584 * Address will be dropped in a given bridge-domain (where 200 is the
585 * bridge-domain-id):
586 * @cliexcmd{l2fib add 52:54:00:53:18:77 200 filter}
587 * Example of show command of the provisioned MAC Addresses and filters:
588 * @cliexstart{show l2fib verbose}
589 * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
590 * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0
591 * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0
592 * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0
593 * 3 l2fib entries
594 * @cliexend
595?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400596/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597VLIB_CLI_COMMAND (l2fib_add_cli, static) = {
598 .path = "l2fib add",
Billy McFall22aa3e92016-09-09 08:46:40 -0400599 .short_help = "l2fib add <mac> <bridge-domain-id> filter | <intf> [static | bvi]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700600 .function = l2fib_add,
601};
Dave Barach97d8dc22016-08-15 15:31:15 -0400602/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700603
604
605static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400606l2fib_test_command_fn (vlib_main_t * vm,
607 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608{
Damjan Marion60706a22021-10-31 19:21:31 +0100609 u8 mac[8], save_mac[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610 u32 bd_index = 0;
611 u32 sw_if_index = 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612 u32 is_add = 0;
613 u32 is_del = 0;
614 u32 is_check = 0;
615 u32 count = 1;
616 int mac_set = 0;
617 int i;
618
Dave Barach97d8dc22016-08-15 15:31:15 -0400619 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620 {
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200621 if (unformat (input, "mac %U", unformat_ethernet_address, mac))
Dave Barach97d8dc22016-08-15 15:31:15 -0400622 mac_set = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623 else if (unformat (input, "add"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400624 is_add = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625 else if (unformat (input, "del"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400626 is_del = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 else if (unformat (input, "check"))
Dave Barach97d8dc22016-08-15 15:31:15 -0400628 is_check = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629 else if (unformat (input, "count %d", &count))
Dave Barach97d8dc22016-08-15 15:31:15 -0400630 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 else
Dave Barach97d8dc22016-08-15 15:31:15 -0400632 break;
633 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
635 if (mac_set == 0)
636 return clib_error_return (0, "mac not set");
637
638 if (is_add == 0 && is_del == 0 && is_check == 0)
Dave Barach97d8dc22016-08-15 15:31:15 -0400639 return clib_error_return (0,
640 "noop: pick at least one of (add,del,check)");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700641
Dave Barach178cf492018-11-13 16:34:13 -0500642 clib_memcpy_fast (save_mac, mac, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643
644 if (is_add)
645 {
646 for (i = 0; i < count; i++)
Dave Barach97d8dc22016-08-15 15:31:15 -0400647 {
Neale Rannsb54d0812018-09-06 06:22:56 -0700648 l2fib_add_entry (mac, bd_index, sw_if_index,
649 L2FIB_ENTRY_RESULT_FLAG_NONE);
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200650 incr_mac_address (mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400651 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652 }
653
654 if (is_check)
655 {
Dave Barach97d8dc22016-08-15 15:31:15 -0400656 BVT (clib_bihash_kv) kv;
657 l2fib_main_t *mp = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658
Damjan Marion95147812020-09-14 12:18:44 +0200659 if (mp->mac_table_initialized == 0)
660 return clib_error_return (0, "mac table is not initialized");
661
Dave Barach178cf492018-11-13 16:34:13 -0500662 clib_memcpy_fast (mac, save_mac, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663
664 for (i = 0; i < count; i++)
Dave Barach97d8dc22016-08-15 15:31:15 -0400665 {
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200666 kv.key = l2fib_make_key (mac, bd_index);
Dave Barach97d8dc22016-08-15 15:31:15 -0400667 if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
668 {
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200669 clib_warning ("key %U AWOL", format_ethernet_address, mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400670 break;
671 }
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200672 incr_mac_address (mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400673 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700674 }
675
676 if (is_del)
677 {
Dave Barach178cf492018-11-13 16:34:13 -0500678 clib_memcpy_fast (mac, save_mac, 6);
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200679
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680 for (i = 0; i < count; i++)
Dave Barach97d8dc22016-08-15 15:31:15 -0400681 {
John Lo7dbd7262018-05-31 10:25:18 -0400682 l2fib_del_entry (mac, bd_index, 0);
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200683 incr_mac_address (mac);
Dave Barach97d8dc22016-08-15 15:31:15 -0400684 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685 }
686
Damjan Marion95147812020-09-14 12:18:44 +0200687 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688}
689
Billy McFall22aa3e92016-09-09 08:46:40 -0400690/*?
691 * The set of '<em>test l2fib</em>' commands allow the L2 FIB table of the default
692 * bridge domain (bridge-domain-id of 0) to be modified.
693 *
694 * @cliexpar
695 * @parblock
696 * Example of how to add a set of 4 sequential MAC Address entries to L2
697 * FIB table of the default bridge-domain:
698 * @cliexcmd{test l2fib add mac 52:54:00:53:00:00 count 4}
699 *
700 * Show the set of 4 sequential MAC Address entries that were added:
701 * @cliexstart{show l2fib verbose}
702 * Mac Address BD Idx Interface Index static filter bvi refresh timestamp
703 * 52:54:00:53:00:00 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
704 * 52:54:00:53:00:01 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
705 * 52:54:00:53:00:03 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
706 * 52:54:00:53:00:02 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0
707 * 4 l2fib entries
708 * @cliexend
709 *
710 * Example of how to check that the set of 4 sequential MAC Address
711 * entries were added to L2 FIB table of the default
712 * bridge-domain. Used a count of 5 to produce an error:
713 *
714 * @cliexcmd{test l2fib check mac 52:54:00:53:00:00 count 5}
715 * The output of the check command is in the log files. Log file
716 * location may vary based on your OS and Version:
717 *
718 * <b><em># tail -f /var/log/messages | grep l2fib_test_command_fn</em></b>
719 *
720 * Sep 7 17:15:24 localhost vnet[4952]: l2fib_test_command_fn:446: key 52:54:00:53:00:04 AWOL
721 *
722 * Example of how to delete a set of 4 sequential MAC Address entries
723 * from L2 FIB table of the default bridge-domain:
724 * @cliexcmd{test l2fib del mac 52:54:00:53:00:00 count 4}
725 * @endparblock
726?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400727/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700728VLIB_CLI_COMMAND (l2fib_test_command, static) = {
729 .path = "test l2fib",
Billy McFall22aa3e92016-09-09 08:46:40 -0400730 .short_help = "test l2fib [add|del|check] mac <base-addr> count <nn>",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731 .function = l2fib_test_command_fn,
732};
Dave Barach97d8dc22016-08-15 15:31:15 -0400733/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734
735
Dave Barach97d8dc22016-08-15 15:31:15 -0400736/**
737 * Delete an entry from the l2fib.
John Lo7dbd7262018-05-31 10:25:18 -0400738 * Return 0 if the entry was deleted, or 1 it was not found or if
739 * sw_if_index is non-zero and does not match that in the entry.
Dave Barach97d8dc22016-08-15 15:31:15 -0400740 */
John Lo7dbd7262018-05-31 10:25:18 -0400741u32
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700742l2fib_del_entry (const u8 * mac, u32 bd_index, u32 sw_if_index)
Dave Barach97d8dc22016-08-15 15:31:15 -0400743{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744 l2fib_entry_result_t result;
Dave Barach97d8dc22016-08-15 15:31:15 -0400745 l2fib_main_t *mp = &l2fib_main;
746 BVT (clib_bihash_kv) kv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747
Damjan Marion95147812020-09-14 12:18:44 +0200748 if (mp->mac_table_initialized == 0)
749 return 1;
750
Dave Barach97d8dc22016-08-15 15:31:15 -0400751 /* set up key */
John Lo7dbd7262018-05-31 10:25:18 -0400752 kv.key = l2fib_make_key (mac, bd_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753
Dave Barach97d8dc22016-08-15 15:31:15 -0400754 if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755 return 1;
756
757 result.raw = kv.value;
758
John Lo7dbd7262018-05-31 10:25:18 -0400759 /* check if sw_if_index of entry match */
760 if ((sw_if_index != 0) && (sw_if_index != result.fields.sw_if_index))
761 return 1;
762
Dave Barach97d8dc22016-08-15 15:31:15 -0400763 /* decrement counter if dynamically learned mac */
Jerome Tollet5f93e3b2020-12-18 09:44:24 +0100764 if (!l2fib_entry_result_is_set_AGE_NOT (&result))
765 {
766 l2_bridge_domain_t *bd_config =
767 vec_elt_at_index (l2input_main.bd_configs, bd_index);
768 if (l2learn_main.global_learn_count)
769 l2learn_main.global_learn_count--;
770 if (bd_config->learn_count)
771 bd_config->learn_count--;
772 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773
Dave Barach97d8dc22016-08-15 15:31:15 -0400774 /* Remove entry from hash table */
775 BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700776 return 0;
777}
778
Dave Barach97d8dc22016-08-15 15:31:15 -0400779/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400780 * Delete an entry from the L2FIB.
Dave Barach97d8dc22016-08-15 15:31:15 -0400781 * The CLI format is:
782 * l2fib del <mac> <bd-id>
783 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784static clib_error_t *
Dave Barach97d8dc22016-08-15 15:31:15 -0400785l2fib_del (vlib_main_t * vm,
786 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787{
Dave Barach97d8dc22016-08-15 15:31:15 -0400788 bd_main_t *bdm = &bd_main;
789 clib_error_t *error = 0;
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200790 u8 mac[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 u32 bd_id;
792 u32 bd_index;
Dave Barach97d8dc22016-08-15 15:31:15 -0400793 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700794
Mohsin Kazmi57938f62017-10-27 21:28:07 +0200795 if (!unformat (input, "%U", unformat_ethernet_address, mac))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700796 {
797 error = clib_error_return (0, "expected mac address `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400798 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799 goto done;
800 }
Dave Barach97d8dc22016-08-15 15:31:15 -0400801
802 if (!unformat (input, "%d", &bd_id))
803 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 error = clib_error_return (0, "expected bridge domain ID `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400805 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400807 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808
809 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
Dave Barach97d8dc22016-08-15 15:31:15 -0400810 if (!p)
811 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812 error = clib_error_return (0, "bridge domain ID %d invalid", bd_id);
813 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400814 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815 bd_index = p[0];
816
Dave Barach97d8dc22016-08-15 15:31:15 -0400817 /* Delete the entry */
John Lo7dbd7262018-05-31 10:25:18 -0400818 if (l2fib_del_entry (mac, bd_index, 0))
Dave Barach97d8dc22016-08-15 15:31:15 -0400819 {
820 error = clib_error_return (0, "mac entry not found");
821 goto done;
822 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823
Dave Barach97d8dc22016-08-15 15:31:15 -0400824done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825 return error;
826}
827
Billy McFall22aa3e92016-09-09 08:46:40 -0400828/*?
829 * This command deletes an existing MAC Address entry from the L2 FIB
830 * table of an existing bridge-domain.
831 *
832 * @cliexpar
833 * Example of how to delete a MAC Address entry from the L2 FIB table of a bridge-domain (where 200 is the bridge-domain-id):
834 * @cliexcmd{l2fib del 52:54:00:53:18:33 200}
835?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400836/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700837VLIB_CLI_COMMAND (l2fib_del_cli, static) = {
838 .path = "l2fib del",
John Lo7dbd7262018-05-31 10:25:18 -0400839 .short_help = "l2fib del <mac> <bridge-domain-id> []",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840 .function = l2fib_del,
841};
Dave Barach97d8dc22016-08-15 15:31:15 -0400842/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700843
Jerome Tollet0f8d1002021-01-07 12:44:17 +0100844static clib_error_t *
845l2fib_set_scan_delay (vlib_main_t *vm, unformat_input_t *input,
846 vlib_cli_command_t *cmd)
847{
848 clib_error_t *error = 0;
849 u32 scan_delay;
850 l2fib_main_t *fm = &l2fib_main;
851
852 if (!unformat (input, "%d", &scan_delay))
853 {
854 error = clib_error_return (0, "expecting delay but got `%U'",
855 format_unformat_error, input);
856 goto done;
857 }
858 fm->event_scan_delay = (f64) (scan_delay) *10e-3;
859 l2fib_flush_all_mac (vlib_get_main ());
860done:
861 return error;
862}
863
864/*?
865 * This command set scan delay (in 1/10s unit)
866 *
867?*/
868VLIB_CLI_COMMAND (l2fib_set_scan_delay_cli, static) = {
869 .path = "set l2fib scan-delay",
870 .short_help = "set l2fib scan-delay <delay>",
871 .function = l2fib_set_scan_delay,
872};
873
John Loda1f2c72017-03-24 20:11:15 -0400874/**
875 Kick off ager to scan MACs to age/delete MAC entries
876*/
877void
878l2fib_start_ager_scan (vlib_main_t * vm)
879{
Eyal Bari24db0ec2017-09-27 21:43:51 +0300880 uword evt = L2_MAC_AGE_PROCESS_EVENT_ONE_PASS;
John Loda1f2c72017-03-24 20:11:15 -0400881
882 /* check if there is at least one bd with mac aging enabled */
Eyal Bari24db0ec2017-09-27 21:43:51 +0300883 l2_bridge_domain_t *bd_config;
John Loda1f2c72017-03-24 20:11:15 -0400884 vec_foreach (bd_config, l2input_main.bd_configs)
Eyal Bari24db0ec2017-09-27 21:43:51 +0300885 {
John Loda1f2c72017-03-24 20:11:15 -0400886 if (bd_config->bd_id != ~0 && bd_config->mac_age != 0)
Eyal Bari24db0ec2017-09-27 21:43:51 +0300887 {
888 evt = L2_MAC_AGE_PROCESS_EVENT_START;
889 break;
890 }
891 }
John Loda1f2c72017-03-24 20:11:15 -0400892
893 vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index,
Eyal Bari24db0ec2017-09-27 21:43:51 +0300894 evt, 0);
John Loda1f2c72017-03-24 20:11:15 -0400895}
896
897/**
Eyal Bari7537e712017-04-27 14:07:55 +0300898 Flush all non static MACs from an interface
John Loda1f2c72017-03-24 20:11:15 -0400899*/
900void
901l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index)
902{
Neale Ranns47a3d992020-09-29 15:38:51 +0000903 l2_input_seq_num_inc (sw_if_index);
John Loda1f2c72017-03-24 20:11:15 -0400904 l2fib_start_ager_scan (vm);
905}
906
907/**
Eyal Bari7537e712017-04-27 14:07:55 +0300908 Flush all non static MACs in a bridge domain
John Loda1f2c72017-03-24 20:11:15 -0400909*/
910void
911l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index)
912{
Eyal Bari7537e712017-04-27 14:07:55 +0300913 l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
John Loda1f2c72017-03-24 20:11:15 -0400914 bd_config->seq_num += 1;
915 l2fib_start_ager_scan (vm);
916}
917
918/**
Eyal Bari7537e712017-04-27 14:07:55 +0300919 Flush all non static MACs - flushes all valid BDs
920*/
921void
922l2fib_flush_all_mac (vlib_main_t * vm)
923{
924 l2_bridge_domain_t *bd_config;
925 vec_foreach (bd_config, l2input_main.bd_configs)
926 if (bd_is_valid (bd_config))
927 bd_config->seq_num += 1;
928
929 l2fib_start_ager_scan (vm);
930}
931
932
933/**
John Loda1f2c72017-03-24 20:11:15 -0400934 Flush MACs, except static ones, associated with an interface
935 The CLI format is:
936 l2fib flush-mac interface <if-name>
937*/
938static clib_error_t *
939l2fib_flush_mac_int (vlib_main_t * vm,
940 unformat_input_t * input, vlib_cli_command_t * cmd)
941{
942 vnet_main_t *vnm = vnet_get_main ();
943 clib_error_t *error = 0;
944 u32 sw_if_index;
945
946 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
947 {
948 error = clib_error_return (0, "unknown interface `%U'",
949 format_unformat_error, input);
950 goto done;
951 }
952
953 l2fib_flush_int_mac (vm, sw_if_index);
954
955done:
956 return error;
957}
958
Eyal Bari7537e712017-04-27 14:07:55 +0300959/**
960 Flush all MACs, except static ones
961 The CLI format is:
962 l2fib flush-mac all
963*/
964static clib_error_t *
965l2fib_flush_mac_all (vlib_main_t * vm,
966 unformat_input_t * input, vlib_cli_command_t * cmd)
967{
968 l2fib_flush_all_mac (vm);
969 return 0;
970}
971
972/*?
973 * This command kick off ager to delete all existing MAC Address entries,
974 * except static ones, associated with an interface from the L2 FIB table.
975 *
976 * @cliexpar
977 * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
978 * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
979?*/
980/* *INDENT-OFF* */
981VLIB_CLI_COMMAND (l2fib_flush_mac_all_cli, static) = {
982 .path = "l2fib flush-mac all",
983 .short_help = "l2fib flush-mac all",
984 .function = l2fib_flush_mac_all,
985};
986/* *INDENT-ON* */
987
John Loda1f2c72017-03-24 20:11:15 -0400988/*?
989 * This command kick off ager to delete all existing MAC Address entries,
990 * except static ones, associated with an interface from the L2 FIB table.
991 *
992 * @cliexpar
993 * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table:
994 * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0}
995?*/
996/* *INDENT-OFF* */
997VLIB_CLI_COMMAND (l2fib_flush_mac_int_cli, static) = {
998 .path = "l2fib flush-mac interface",
999 .short_help = "l2fib flush-mac interface <if-name>",
1000 .function = l2fib_flush_mac_int,
1001};
1002/* *INDENT-ON* */
1003
1004/**
1005 Flush bridge-domain MACs except static ones.
1006 The CLI format is:
1007 l2fib flush-mac bridge-domain <bd-id>
1008*/
1009static clib_error_t *
1010l2fib_flush_mac_bd (vlib_main_t * vm,
1011 unformat_input_t * input, vlib_cli_command_t * cmd)
1012{
1013 bd_main_t *bdm = &bd_main;
1014 clib_error_t *error = 0;
1015 u32 bd_index, bd_id;
1016 uword *p;
1017
1018 if (!unformat (input, "%d", &bd_id))
1019 {
1020 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
1021 format_unformat_error, input);
1022 goto done;
1023 }
1024
1025 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1026 if (p)
1027 bd_index = *p;
1028 else
1029 return clib_error_return (0, "No such bridge domain %d", bd_id);
1030
1031 l2fib_flush_bd_mac (vm, bd_index);
1032
1033done:
1034 return error;
1035}
1036
1037/*?
1038 * This command kick off ager to delete all existing MAC Address entries,
1039 * except static ones, in a bridge domain from the L2 FIB table.
1040 *
1041 * @cliexpar
1042 * Example of how to flush MAC Address entries learned in a bridge domain from the L2 FIB table:
1043 * @cliexcmd{l2fib flush-mac bridge-domain 1000}
1044?*/
1045/* *INDENT-OFF* */
1046VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = {
1047 .path = "l2fib flush-mac bridge-domain",
1048 .short_help = "l2fib flush-mac bridge-domain <bd-id>",
1049 .function = l2fib_flush_mac_bd,
1050};
1051/* *INDENT-ON* */
1052
Eyal Bariafc47aa2017-04-20 14:45:17 +03001053clib_error_t *
1054l2fib_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
1055{
1056 l2_input_config_t *config = l2input_intf_config (sw_if_index);
Neale Ranns47a3d992020-09-29 15:38:51 +00001057 if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0 &&
1058 l2_input_is_bridge (config))
Eyal Bariafc47aa2017-04-20 14:45:17 +03001059 l2fib_flush_int_mac (vnm->vlib_main, sw_if_index);
1060 return 0;
1061}
1062
1063VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2fib_sw_interface_up_down);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064
Dave Barach97d8dc22016-08-15 15:31:15 -04001065BVT (clib_bihash) * get_mac_table (void)
1066{
1067 l2fib_main_t *mp = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 return &mp->mac_table;
1069}
1070
John Lo8d00fff2017-08-03 00:35:36 -04001071static_always_inline void *
1072allocate_mac_evt_buf (u32 client, u32 client_index)
1073{
1074 l2fib_main_t *fm = &l2fib_main;
1075 vl_api_l2_macs_event_t *mp = vl_msg_api_alloc
1076 (sizeof (*mp) + (fm->max_macs_in_event * sizeof (vl_api_mac_entry_t)));
Filip Tehlar5a9d2a12021-06-22 21:20:29 +00001077 mp->_vl_msg_id = htons (l2input_main.msg_id_base + VL_API_L2_MACS_EVENT);
John Lo8d00fff2017-08-03 00:35:36 -04001078 mp->pid = htonl (client);
1079 mp->client_index = client_index;
1080 return mp;
1081}
1082
1083static_always_inline f64
1084l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
1085{
1086 l2fib_main_t *fm = &l2fib_main;
1087 l2learn_main_t *lm = &l2learn_main;
1088
1089 BVT (clib_bihash) * h = &fm->mac_table;
1090 int i, j, k;
1091 f64 last_start = start_time;
1092 f64 accum_t = 0;
1093 f64 delta_t = 0;
1094 u32 evt_idx = 0;
1095 u32 learn_count = 0;
1096 u32 client = lm->client_pid;
1097 u32 cl_idx = lm->client_index;
1098 vl_api_l2_macs_event_t *mp = 0;
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001099 vl_api_registration_t *reg = 0;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001100 u32 bd_index;
1101 static u32 *bd_learn_counts = 0;
John Lo8d00fff2017-08-03 00:35:36 -04001102
Dave Barach32dcd3b2019-07-08 12:25:38 -04001103 /* Don't scan the l2 fib if it hasn't been instantiated yet */
1104 if (alloc_arena (h) == 0)
1105 return 0.0;
1106
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001107 vec_reset_length (bd_learn_counts);
1108 vec_validate (bd_learn_counts, vec_len (l2input_main.bd_configs) - 1);
1109
John Lo8d00fff2017-08-03 00:35:36 -04001110 if (client)
1111 {
1112 mp = allocate_mac_evt_buf (client, cl_idx);
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001113 reg = vl_api_client_index_to_registration (lm->client_index);
John Lo8d00fff2017-08-03 00:35:36 -04001114 }
1115
1116 for (i = 0; i < h->nbuckets; i++)
1117 {
1118 /* allow no more than 20us without a pause */
1119 delta_t = vlib_time_now (vm) - last_start;
1120 if (delta_t > 20e-6)
1121 {
1122 vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001123 /* in case a new bd was created while sleeping */
1124 vec_validate (bd_learn_counts,
1125 vec_len (l2input_main.bd_configs) - 1);
John Lo8d00fff2017-08-03 00:35:36 -04001126 last_start = vlib_time_now (vm);
1127 accum_t += delta_t;
1128 }
1129
1130 if (i < (h->nbuckets - 3))
1131 {
Dave Barach16e4a4a2020-04-16 12:00:14 -04001132 BVT (clib_bihash_bucket) * b =
1133 BV (clib_bihash_get_bucket) (h, i + 3);
Damjan Marionaf7fb042021-07-15 11:54:41 +02001134 clib_prefetch_load (b);
Dave Barach16e4a4a2020-04-16 12:00:14 -04001135 b = BV (clib_bihash_get_bucket) (h, i + 1);
1136 if (!BV (clib_bihash_bucket_is_empty) (b))
John Lo8d00fff2017-08-03 00:35:36 -04001137 {
1138 BVT (clib_bihash_value) * v =
1139 BV (clib_bihash_get_value) (h, b->offset);
Damjan Marionaf7fb042021-07-15 11:54:41 +02001140 clib_prefetch_load (v);
John Lo8d00fff2017-08-03 00:35:36 -04001141 }
1142 }
1143
Dave Barach16e4a4a2020-04-16 12:00:14 -04001144 BVT (clib_bihash_bucket) * b = BV (clib_bihash_get_bucket) (h, i);
1145 if (BV (clib_bihash_bucket_is_empty) (b))
John Lo8d00fff2017-08-03 00:35:36 -04001146 continue;
1147 BVT (clib_bihash_value) * v = BV (clib_bihash_get_value) (h, b->offset);
1148 for (j = 0; j < (1 << b->log2_pages); j++)
1149 {
1150 for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
1151 {
Dave Barachb9c8c572023-03-16 13:03:47 -04001152 if (BV (clib_bihash_is_free) (&v->kvp[k]))
John Lo8d00fff2017-08-03 00:35:36 -04001153 continue;
1154
1155 l2fib_entry_key_t key = {.raw = v->kvp[k].key };
1156 l2fib_entry_result_t result = {.raw = v->kvp[k].value };
1157
Neale Rannsb54d0812018-09-06 06:22:56 -07001158 if (!l2fib_entry_result_is_set_AGE_NOT (&result))
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001159 {
1160 learn_count++;
1161 vec_elt (bd_learn_counts, key.fields.bd_index)++;
1162 }
John Lo8d00fff2017-08-03 00:35:36 -04001163
John Lo8d00fff2017-08-03 00:35:36 -04001164 if (client)
1165 {
Eyal Bari24db0ec2017-09-27 21:43:51 +03001166 if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event))
1167 {
1168 /* event message full, send it and start a new one */
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001169 if (reg && vl_api_can_send_msg (reg))
Eyal Bari24db0ec2017-09-27 21:43:51 +03001170 {
1171 mp->n_macs = htonl (evt_idx);
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001172 vl_api_send_msg (reg, (u8 *) mp);
Eyal Bari24db0ec2017-09-27 21:43:51 +03001173 mp = allocate_mac_evt_buf (client, cl_idx);
1174 }
1175 else
1176 {
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001177 if (reg)
Dave Barach59b25652017-09-10 15:04:27 -04001178 clib_warning ("MAC event to pid %d queue stuffed!"
1179 " %d MAC entries lost", client,
1180 evt_idx);
Eyal Bari24db0ec2017-09-27 21:43:51 +03001181 }
1182 evt_idx = 0;
1183 }
1184
Neale Rannsb54d0812018-09-06 06:22:56 -07001185 if (l2fib_entry_result_is_set_LRN_EVT (&result))
John Lo8d00fff2017-08-03 00:35:36 -04001186 {
1187 /* copy mac entry to event msg */
Dave Barach178cf492018-11-13 16:34:13 -05001188 clib_memcpy_fast (mp->mac[evt_idx].mac_addr,
1189 key.fields.mac, 6);
Neale Rannsb54d0812018-09-06 06:22:56 -07001190 mp->mac[evt_idx].action =
1191 l2fib_entry_result_is_set_LRN_MOV (&result) ?
Jakub Grajciar145e3302019-10-24 13:52:42 +02001192 (vl_api_mac_event_action_t) MAC_EVENT_ACTION_MOVE
1193 : (vl_api_mac_event_action_t) MAC_EVENT_ACTION_ADD;
1194 mp->mac[evt_idx].action =
1195 htonl (mp->mac[evt_idx].action);
John Lo8d00fff2017-08-03 00:35:36 -04001196 mp->mac[evt_idx].sw_if_index =
1197 htonl (result.fields.sw_if_index);
John Loe23c99e2018-03-13 21:53:18 -04001198 /* clear event bits and update mac entry */
Neale Rannsb54d0812018-09-06 06:22:56 -07001199 l2fib_entry_result_clear_LRN_EVT (&result);
1200 l2fib_entry_result_clear_LRN_MOV (&result);
John Lo8d00fff2017-08-03 00:35:36 -04001201 BVT (clib_bihash_kv) kv;
1202 kv.key = key.raw;
1203 kv.value = result.raw;
1204 BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1);
1205 evt_idx++;
1206 continue; /* skip aging */
1207 }
1208 }
1209
Neale Rannsb54d0812018-09-06 06:22:56 -07001210 if (event_only || l2fib_entry_result_is_set_AGE_NOT (&result))
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -07001211 continue; /* skip aging - static_mac always age_not */
John Lo8d00fff2017-08-03 00:35:36 -04001212
1213 /* start aging processing */
1214 u32 bd_index = key.fields.bd_index;
1215 u32 sw_if_index = result.fields.sw_if_index;
Neale Ranns47a3d992020-09-29 15:38:51 +00001216 u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index);
1217 if (result.fields.sn != sn)
John Lo8d00fff2017-08-03 00:35:36 -04001218 goto age_out; /* stale mac */
1219
1220 l2_bridge_domain_t *bd_config =
1221 vec_elt_at_index (l2input_main.bd_configs, bd_index);
1222
1223 if (bd_config->mac_age == 0)
1224 continue; /* skip aging */
1225
1226 i16 delta = (u8) (start_time / 60) - result.fields.timestamp;
1227 delta += delta < 0 ? 256 : 0;
1228
1229 if (delta < bd_config->mac_age)
1230 continue; /* still valid */
1231
1232 age_out:
1233 if (client)
1234 {
1235 /* copy mac entry to event msg */
Dave Barach178cf492018-11-13 16:34:13 -05001236 clib_memcpy_fast (mp->mac[evt_idx].mac_addr, key.fields.mac,
1237 6);
Jakub Grajciar145e3302019-10-24 13:52:42 +02001238 mp->mac[evt_idx].action =
1239 (vl_api_mac_event_action_t) MAC_EVENT_ACTION_DELETE;
1240 mp->mac[evt_idx].action = htonl (mp->mac[evt_idx].action);
John Lo8d00fff2017-08-03 00:35:36 -04001241 mp->mac[evt_idx].sw_if_index =
1242 htonl (result.fields.sw_if_index);
1243 evt_idx++;
1244 }
1245 /* delete mac entry */
1246 BVT (clib_bihash_kv) kv;
1247 kv.key = key.raw;
1248 BV (clib_bihash_add_del) (&fm->mac_table, &kv, 0);
1249 learn_count--;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001250 vec_elt (bd_learn_counts, key.fields.bd_index)--;
Dave Barach28374ca2018-08-07 12:46:18 -04001251 /*
1252 * Note: we may have just freed the bucket's backing
1253 * storage, so check right here...
1254 */
Dave Barach16e4a4a2020-04-16 12:00:14 -04001255 if (BV (clib_bihash_bucket_is_empty) (b))
Dave Barach28374ca2018-08-07 12:46:18 -04001256 goto doublebreak;
John Lo8d00fff2017-08-03 00:35:36 -04001257 }
1258 v++;
1259 }
Dave Barach28374ca2018-08-07 12:46:18 -04001260 doublebreak:
1261 ;
John Lo8d00fff2017-08-03 00:35:36 -04001262 }
1263
1264 /* keep learn count consistent */
1265 l2learn_main.global_learn_count = learn_count;
Jerome Tollet5f93e3b2020-12-18 09:44:24 +01001266 vec_foreach_index (bd_index, l2input_main.bd_configs)
1267 {
1268 vec_elt (l2input_main.bd_configs, bd_index).learn_count =
1269 vec_elt (bd_learn_counts, bd_index);
1270 }
John Lo8d00fff2017-08-03 00:35:36 -04001271
1272 if (mp)
1273 {
1274 /* send any outstanding mac event message else free message buffer */
1275 if (evt_idx)
1276 {
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001277 if (reg && vl_api_can_send_msg (reg))
John Lo8d00fff2017-08-03 00:35:36 -04001278 {
1279 mp->n_macs = htonl (evt_idx);
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001280 vl_api_send_msg (reg, (u8 *) mp);
John Lo8d00fff2017-08-03 00:35:36 -04001281 }
1282 else
1283 {
Florin Corasaf0ff5a2018-01-10 08:17:03 -08001284 if (reg)
Dave Barach59b25652017-09-10 15:04:27 -04001285 clib_warning ("MAC event to pid %d queue stuffed!"
1286 " %d MAC entries lost", client, evt_idx);
John Lo8d00fff2017-08-03 00:35:36 -04001287 vl_msg_api_free (mp);
1288 }
1289 }
1290 else
1291 vl_msg_api_free (mp);
1292 }
1293 return delta_t + accum_t;
1294}
1295
Damjan Mariond171d482016-12-05 14:16:38 +01001296static uword
1297l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
1298 vlib_frame_t * f)
1299{
1300 uword event_type, *event_data = 0;
John Lo8d00fff2017-08-03 00:35:36 -04001301 l2fib_main_t *fm = &l2fib_main;
1302 l2learn_main_t *lm = &l2learn_main;
Damjan Mariond171d482016-12-05 14:16:38 +01001303 bool enabled = 0;
John Lo7f358b32018-04-28 01:19:24 -04001304 f64 start_time, next_age_scan_time = CLIB_TIME_MAX;
Damjan Mariond171d482016-12-05 14:16:38 +01001305
1306 while (1)
1307 {
Eyal Bari24db0ec2017-09-27 21:43:51 +03001308 if (lm->client_pid)
1309 vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay);
1310 else if (enabled)
John Lo8d00fff2017-08-03 00:35:36 -04001311 {
Eyal Bari24db0ec2017-09-27 21:43:51 +03001312 f64 t = next_age_scan_time - vlib_time_now (vm);
1313 vlib_process_wait_for_event_or_clock (vm, t);
John Lo8d00fff2017-08-03 00:35:36 -04001314 }
Damjan Mariond171d482016-12-05 14:16:38 +01001315 else
1316 vlib_process_wait_for_event (vm);
1317
1318 event_type = vlib_process_get_events (vm, &event_data);
1319 vec_reset_length (event_data);
1320
John Lo8d00fff2017-08-03 00:35:36 -04001321 start_time = vlib_time_now (vm);
Eyal Bari24db0ec2017-09-27 21:43:51 +03001322 enum
1323 { SCAN_MAC_AGE, SCAN_MAC_EVENT, SCAN_DISABLE } scan = SCAN_MAC_AGE;
John Lo8d00fff2017-08-03 00:35:36 -04001324
Damjan Mariond171d482016-12-05 14:16:38 +01001325 switch (event_type)
1326 {
John Lo8d00fff2017-08-03 00:35:36 -04001327 case ~0: /* timer expired */
Eyal Bari24db0ec2017-09-27 21:43:51 +03001328 if (lm->client_pid != 0 && start_time < next_age_scan_time)
John Lo8d00fff2017-08-03 00:35:36 -04001329 scan = SCAN_MAC_EVENT;
Damjan Mariond171d482016-12-05 14:16:38 +01001330 break;
John Lo8d00fff2017-08-03 00:35:36 -04001331
Damjan Mariond171d482016-12-05 14:16:38 +01001332 case L2_MAC_AGE_PROCESS_EVENT_START:
1333 enabled = 1;
1334 break;
John Lo8d00fff2017-08-03 00:35:36 -04001335
Damjan Mariond171d482016-12-05 14:16:38 +01001336 case L2_MAC_AGE_PROCESS_EVENT_STOP:
1337 enabled = 0;
Eyal Bari24db0ec2017-09-27 21:43:51 +03001338 scan = SCAN_DISABLE;
1339 break;
John Lo8d00fff2017-08-03 00:35:36 -04001340
John Loda1f2c72017-03-24 20:11:15 -04001341 case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS:
John Loda1f2c72017-03-24 20:11:15 -04001342 break;
John Lo8d00fff2017-08-03 00:35:36 -04001343
Damjan Mariond171d482016-12-05 14:16:38 +01001344 default:
1345 ASSERT (0);
1346 }
Eyal Bari7537e712017-04-27 14:07:55 +03001347
John Lo8d00fff2017-08-03 00:35:36 -04001348 if (scan == SCAN_MAC_EVENT)
1349 l2fib_main.evt_scan_duration = l2fib_scan (vm, start_time, 1);
1350 else
Eyal Bari24db0ec2017-09-27 21:43:51 +03001351 {
1352 if (scan == SCAN_MAC_AGE)
1353 l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0);
1354 if (scan == SCAN_DISABLE)
1355 {
1356 l2fib_main.age_scan_duration = 0;
1357 l2fib_main.evt_scan_duration = 0;
1358 }
1359 /* schedule next scan */
1360 if (enabled)
1361 next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL;
1362 else
John Lo7f358b32018-04-28 01:19:24 -04001363 next_age_scan_time = CLIB_TIME_MAX;
Eyal Bari24db0ec2017-09-27 21:43:51 +03001364 }
Damjan Mariond171d482016-12-05 14:16:38 +01001365 }
1366 return 0;
1367}
1368
1369/* *INDENT-OFF* */
1370VLIB_REGISTER_NODE (l2fib_mac_age_scanner_process_node) = {
1371 .function = l2fib_mac_age_scanner_process,
1372 .type = VLIB_NODE_TYPE_PROCESS,
1373 .name = "l2fib-mac-age-scanner-process",
1374};
1375/* *INDENT-ON* */
1376
Dave Barach97d8dc22016-08-15 15:31:15 -04001377clib_error_t *
1378l2fib_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001379{
Dave Barach97d8dc22016-08-15 15:31:15 -04001380 l2fib_main_t *mp = &l2fib_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381 l2fib_entry_key_t test_key;
1382 u8 test_mac[6];
Dave Barach97d8dc22016-08-15 15:31:15 -04001383
Ed Warnickecb9cada2015-12-08 15:45:58 -07001384 mp->vlib_main = vm;
Dave Barach97d8dc22016-08-15 15:31:15 -04001385 mp->vnet_main = vnet_get_main ();
Damjan Marion95147812020-09-14 12:18:44 +02001386 if (mp->mac_table_n_buckets == 0)
1387 mp->mac_table_n_buckets = L2FIB_NUM_BUCKETS;
1388 if (mp->mac_table_memory_size == 0)
1389 mp->mac_table_memory_size = L2FIB_MEMORY_SIZE;
1390 mp->mac_table_initialized = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001391
Dave Barach97d8dc22016-08-15 15:31:15 -04001392 /* verify the key constructor is good, since it is endian-sensitive */
Dave Barachb7b92992018-10-17 10:38:51 -04001393 clib_memset (test_mac, 0, sizeof (test_mac));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 test_mac[0] = 0x11;
1395 test_key.raw = 0;
Dave Barach97d8dc22016-08-15 15:31:15 -04001396 test_key.raw = l2fib_make_key ((u8 *) & test_mac, 0x1234);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 ASSERT (test_key.fields.mac[0] == 0x11);
1398 ASSERT (test_key.fields.bd_index == 0x1234);
1399
1400 return 0;
1401}
1402
1403VLIB_INIT_FUNCTION (l2fib_init);
1404
Damjan Marion95147812020-09-14 12:18:44 +02001405static clib_error_t *
1406lfib_config (vlib_main_t * vm, unformat_input_t * input)
1407{
1408 l2fib_main_t *lm = &l2fib_main;
1409 uword table_size = ~0;
1410 u32 n_buckets = ~0;
1411
1412 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1413 {
1414 if (unformat (input, "table-size %U", unformat_memory_size,
1415 &table_size))
1416 ;
1417 else if (unformat (input, "num-buckets %u", &n_buckets))
1418 ;
1419 else
1420 return clib_error_return (0, "unknown input `%U'",
1421 format_unformat_error, input);
1422 }
1423
1424 if (n_buckets != ~0)
1425 {
1426 if (!is_pow2 (n_buckets))
1427 return clib_error_return (0, "num-buckets must be power of 2");
1428 lm->mac_table_n_buckets = n_buckets;
1429 }
1430
1431 if (table_size != ~0)
1432 lm->mac_table_memory_size = table_size;
1433 return 0;
1434}
1435
1436VLIB_CONFIG_FUNCTION (lfib_config, "l2fib");
1437
Dave Barach97d8dc22016-08-15 15:31:15 -04001438/*
1439 * fd.io coding-style-patch-verification: ON
1440 *
1441 * Local Variables:
1442 * eval: (c-set-style "gnu")
1443 * End:
1444 */