Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * l2_api.c - layer 2 forwarding api
4 : *
5 : * Copyright (c) 2016 Cisco and/or its affiliates.
6 : * Copyright (c) 2022 Nordix Foundation.
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at:
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : *------------------------------------------------------------------
19 : */
20 :
21 : #include <vnet/vnet.h>
22 : #include <vlibmemory/api.h>
23 :
24 : #include <vnet/interface.h>
25 : #include <vnet/api_errno.h>
26 : #include <vnet/l2/l2_input.h>
27 : #include <vnet/l2/l2_fib.h>
28 : #include <vnet/l2/l2_vtr.h>
29 : #include <vnet/l2/l2_learn.h>
30 : #include <vnet/l2/l2_bd.h>
31 : #include <vnet/l2/l2_bvi.h>
32 : #include <vnet/l2/l2_arp_term.h>
33 : #include <vnet/ip/ip_types_api.h>
34 : #include <vnet/ethernet/ethernet_types_api.h>
35 :
36 : #include <vnet/format_fns.h>
37 : #include <vnet/l2/l2.api_enum.h>
38 : #include <vnet/l2/l2.api_types.h>
39 :
40 : #define REPLY_MSG_ID_BASE l2input_main.msg_id_base
41 : #include <vlibapi/api_helper_macros.h>
42 :
43 : static void
44 0 : send_l2_xconnect_details (vl_api_registration_t * reg, u32 context,
45 : u32 rx_sw_if_index, u32 tx_sw_if_index)
46 : {
47 : vl_api_l2_xconnect_details_t *mp;
48 :
49 0 : mp = vl_msg_api_alloc (sizeof (*mp));
50 0 : clib_memset (mp, 0, sizeof (*mp));
51 0 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_L2_XCONNECT_DETAILS);
52 0 : mp->context = context;
53 0 : mp->rx_sw_if_index = htonl (rx_sw_if_index);
54 0 : mp->tx_sw_if_index = htonl (tx_sw_if_index);
55 :
56 0 : vl_api_send_msg (reg, (u8 *) mp);
57 0 : }
58 :
59 : static void
60 0 : vl_api_l2_xconnect_dump_t_handler (vl_api_l2_xconnect_dump_t * mp)
61 : {
62 : vl_api_registration_t *reg;
63 0 : l2input_main_t *l2im = &l2input_main;
64 : u32 sw_if_index;
65 : l2_input_config_t *config;
66 :
67 0 : reg = vl_api_client_index_to_registration (mp->client_index);
68 0 : if (!reg)
69 0 : return;
70 :
71 : /* *INDENT-OFF* */
72 0 : vec_foreach_index (sw_if_index, l2im->configs)
73 : {
74 0 : config = vec_elt_at_index (l2im->configs, sw_if_index);
75 0 : if (l2_input_is_xconnect (config))
76 0 : send_l2_xconnect_details (reg, mp->context, sw_if_index,
77 : config->output_sw_if_index);
78 : }
79 : /* *INDENT-ON* */
80 : }
81 :
82 : static void
83 0 : vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp)
84 : {
85 0 : int rv = 0;
86 : vl_api_l2_fib_clear_table_reply_t *rmp;
87 :
88 : /* Clear all MACs including static MACs */
89 0 : l2fib_clear_table ();
90 :
91 0 : REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY);
92 : }
93 :
94 : static void
95 39 : send_l2fib_table_entry (vpe_api_main_t * am,
96 : vl_api_registration_t * reg,
97 : l2fib_entry_key_t * l2fe_key,
98 : l2fib_entry_result_t * l2fe_res, u32 context)
99 : {
100 : vl_api_l2_fib_table_details_t *mp;
101 :
102 39 : mp = vl_msg_api_alloc (sizeof (*mp));
103 39 : clib_memset (mp, 0, sizeof (*mp));
104 39 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_L2_FIB_TABLE_DETAILS);
105 :
106 39 : mp->bd_id =
107 39 : ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id);
108 :
109 39 : mac_address_encode ((mac_address_t *) l2fe_key->fields.mac, mp->mac);
110 39 : mp->sw_if_index = ntohl (l2fe_res->fields.sw_if_index);
111 39 : mp->static_mac = (l2fib_entry_result_is_set_STATIC (l2fe_res) ? 1 : 0);
112 39 : mp->filter_mac = (l2fib_entry_result_is_set_FILTER (l2fe_res) ? 1 : 0);
113 39 : mp->bvi_mac = (l2fib_entry_result_is_set_BVI (l2fe_res) ? 1 : 0);
114 39 : mp->context = context;
115 :
116 39 : vl_api_send_msg (reg, (u8 *) mp);
117 39 : }
118 :
119 : static void
120 19 : vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp)
121 : {
122 19 : vpe_api_main_t *am = &vpe_api_main;
123 19 : bd_main_t *bdm = &bd_main;
124 19 : l2fib_entry_key_t *l2fe_key = NULL;
125 19 : l2fib_entry_result_t *l2fe_res = NULL;
126 19 : u32 ni, bd_id = ntohl (mp->bd_id);
127 : u32 bd_index;
128 : vl_api_registration_t *reg;
129 : uword *p;
130 :
131 19 : reg = vl_api_client_index_to_registration (mp->client_index);
132 19 : if (!reg)
133 8 : return;
134 :
135 : /* see l2fib_table_dump: ~0 means "any" */
136 19 : if (bd_id == ~0)
137 0 : bd_index = ~0;
138 : else
139 : {
140 19 : p = hash_get (bdm->bd_index_by_bd_id, bd_id);
141 19 : if (p == 0)
142 8 : return;
143 :
144 11 : bd_index = p[0];
145 : }
146 :
147 11 : l2fib_table_dump (bd_index, &l2fe_key, &l2fe_res);
148 :
149 50 : vec_foreach_index (ni, l2fe_key)
150 : {
151 39 : send_l2fib_table_entry (am, reg, vec_elt_at_index (l2fe_key, ni),
152 39 : vec_elt_at_index (l2fe_res, ni), mp->context);
153 : }
154 11 : vec_free (l2fe_key);
155 11 : vec_free (l2fe_res);
156 : }
157 :
158 : static void
159 1416 : vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp)
160 : {
161 1416 : bd_main_t *bdm = &bd_main;
162 1416 : l2input_main_t *l2im = &l2input_main;
163 : vl_api_l2fib_add_del_reply_t *rmp;
164 1416 : int rv = 0;
165 1416 : u32 bd_id = ntohl (mp->bd_id);
166 1416 : uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
167 :
168 1416 : if (!p)
169 : {
170 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
171 0 : goto bad_sw_if_index;
172 : }
173 1416 : u32 bd_index = p[0];
174 :
175 : mac_address_t mac;
176 :
177 1416 : mac_address_decode (mp->mac, &mac);
178 1416 : if (mp->is_add)
179 : {
180 1380 : if (mp->filter_mac)
181 0 : l2fib_add_filter_entry (mac.bytes, bd_index);
182 : else
183 : {
184 1380 : l2fib_entry_result_flags_t flags = L2FIB_ENTRY_RESULT_FLAG_NONE;
185 1380 : u32 sw_if_index = ntohl (mp->sw_if_index);
186 1380 : VALIDATE_SW_IF_INDEX (mp);
187 1380 : if (vec_len (l2im->configs) <= sw_if_index)
188 : {
189 0 : rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
190 0 : goto bad_sw_if_index;
191 : }
192 : else
193 : {
194 : l2_input_config_t *config;
195 1380 : config = vec_elt_at_index (l2im->configs, sw_if_index);
196 1380 : if (!l2_input_is_bridge (config))
197 : {
198 0 : rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
199 0 : goto bad_sw_if_index;
200 : }
201 : }
202 1380 : if (mp->static_mac)
203 1380 : flags |= L2FIB_ENTRY_RESULT_FLAG_STATIC;
204 1380 : if (mp->bvi_mac)
205 0 : flags |= L2FIB_ENTRY_RESULT_FLAG_BVI;
206 1380 : l2fib_add_entry (mac.bytes, bd_index, sw_if_index, flags);
207 : }
208 : }
209 : else
210 : {
211 36 : u32 sw_if_index = ntohl (mp->sw_if_index);
212 36 : if (l2fib_del_entry (mac.bytes, bd_index, sw_if_index))
213 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
214 : }
215 :
216 36 : BAD_SW_IF_INDEX_LABEL;
217 :
218 1416 : REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY);
219 : }
220 :
221 : static void
222 4 : vl_api_want_l2_macs_events2_t_handler (vl_api_want_l2_macs_events2_t *mp)
223 : {
224 4 : int rv = 0;
225 : vl_api_want_l2_macs_events2_reply_t *rmp;
226 4 : l2learn_main_t *lm = &l2learn_main;
227 4 : l2fib_main_t *fm = &l2fib_main;
228 4 : u32 pid = ntohl (mp->pid);
229 :
230 4 : if (mp->enable_disable)
231 : {
232 2 : if ((lm->client_pid == 0) || (lm->client_pid == pid))
233 : {
234 2 : if (mp->max_macs_in_event)
235 2 : fm->max_macs_in_event = mp->max_macs_in_event * 10;
236 : else
237 : {
238 0 : rv = VNET_API_ERROR_INVALID_VALUE;
239 0 : goto exit;
240 : }
241 :
242 : /* if scan_delay was not set before */
243 2 : if (fm->event_scan_delay == 0.0)
244 0 : fm->event_scan_delay = (f64) (10) * 10e-3;
245 :
246 2 : lm->client_pid = pid;
247 2 : lm->client_index = mp->client_index;
248 2 : l2fib_flush_all_mac (vlib_get_main ());
249 : }
250 0 : else if (lm->client_pid != pid)
251 : {
252 0 : rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT;
253 0 : goto exit;
254 : }
255 : }
256 2 : else if (lm->client_pid)
257 : {
258 2 : lm->client_pid = 0;
259 2 : lm->client_index = 0;
260 : }
261 :
262 0 : exit:
263 4 : REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS2_REPLY);
264 : }
265 :
266 : static void
267 6 : vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t *mp)
268 : {
269 6 : int rv = 0;
270 : vl_api_want_l2_macs_events_reply_t *rmp;
271 6 : l2learn_main_t *lm = &l2learn_main;
272 6 : l2fib_main_t *fm = &l2fib_main;
273 6 : u32 pid = ntohl (mp->pid);
274 6 : u32 learn_limit = ntohl (mp->learn_limit);
275 :
276 6 : if (mp->enable_disable)
277 : {
278 4 : if ((lm->client_pid == 0) || (lm->client_pid == pid))
279 : {
280 4 : if ((mp->max_macs_in_event == 0) || (mp->scan_delay == 0) ||
281 4 : (learn_limit == 0) || (learn_limit > L2LEARN_DEFAULT_LIMIT))
282 : {
283 0 : rv = VNET_API_ERROR_INVALID_VALUE;
284 0 : goto exit;
285 : }
286 4 : lm->client_pid = pid;
287 4 : lm->client_index = mp->client_index;
288 :
289 4 : fm->max_macs_in_event = mp->max_macs_in_event * 10;
290 4 : fm->event_scan_delay = (f64) (mp->scan_delay) * 10e-3;
291 :
292 : /* change learn limit and flush all learned MACs */
293 4 : lm->global_learn_limit = learn_limit;
294 4 : l2fib_flush_all_mac (vlib_get_main ());
295 : }
296 0 : else if (lm->client_pid != pid)
297 : {
298 0 : rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT;
299 0 : goto exit;
300 : }
301 : }
302 2 : else if (lm->client_pid)
303 : {
304 2 : lm->client_pid = 0;
305 2 : lm->client_index = 0;
306 2 : if (learn_limit && (learn_limit <= L2LEARN_DEFAULT_LIMIT))
307 2 : lm->global_learn_limit = learn_limit;
308 : else
309 0 : lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT;
310 : }
311 :
312 0 : exit:
313 6 : REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS_REPLY);
314 : }
315 :
316 : static void
317 1 : vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp)
318 : {
319 1 : int rv = 0;
320 1 : vlib_main_t *vm = vlib_get_main ();
321 : vl_api_l2fib_flush_int_reply_t *rmp;
322 :
323 1 : VALIDATE_SW_IF_INDEX (mp);
324 :
325 1 : u32 sw_if_index = ntohl (mp->sw_if_index);
326 1 : l2fib_flush_int_mac (vm, sw_if_index);
327 :
328 1 : BAD_SW_IF_INDEX_LABEL;
329 1 : REPLY_MACRO (VL_API_L2FIB_FLUSH_INT_REPLY);
330 : }
331 :
332 : static void
333 1 : vl_api_l2fib_flush_all_t_handler (vl_api_l2fib_flush_all_t * mp)
334 : {
335 1 : int rv = 0;
336 : vl_api_l2fib_flush_all_reply_t *rmp;
337 :
338 1 : l2fib_flush_all_mac (vlib_get_main ());
339 1 : REPLY_MACRO (VL_API_L2FIB_FLUSH_ALL_REPLY);
340 : }
341 :
342 : static void
343 1 : vl_api_l2fib_flush_bd_t_handler (vl_api_l2fib_flush_bd_t * mp)
344 : {
345 1 : int rv = 0;
346 1 : vlib_main_t *vm = vlib_get_main ();
347 1 : bd_main_t *bdm = &bd_main;
348 : vl_api_l2fib_flush_bd_reply_t *rmp;
349 :
350 1 : u32 bd_id = ntohl (mp->bd_id);
351 1 : uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
352 1 : if (p == 0)
353 : {
354 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
355 0 : goto out;
356 : }
357 1 : l2fib_flush_bd_mac (vm, *p);
358 1 : out:
359 1 : REPLY_MACRO (VL_API_L2FIB_FLUSH_BD_REPLY);
360 : }
361 :
362 : static void
363 2 : vl_api_l2fib_set_scan_delay_t_handler (vl_api_l2fib_set_scan_delay_t *mp)
364 : {
365 2 : int rv = 0;
366 2 : l2fib_main_t *fm = &l2fib_main;
367 : vl_api_l2fib_set_scan_delay_reply_t *rmp;
368 2 : u16 scan_delay = ntohs (mp->scan_delay);
369 :
370 2 : if (mp->scan_delay)
371 : {
372 2 : fm->event_scan_delay = (f64) (scan_delay) *10e-3;
373 2 : l2fib_flush_all_mac (vlib_get_main ());
374 : }
375 : else
376 : {
377 0 : rv = VNET_API_ERROR_INVALID_VALUE;
378 0 : goto exit;
379 : }
380 :
381 2 : exit:
382 2 : REPLY_MACRO (VL_API_L2FIB_SET_SCAN_DELAY_REPLY);
383 : }
384 :
385 : static void
386 0 : vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp)
387 : {
388 : vl_api_l2_flags_reply_t *rmp;
389 0 : int rv = 0;
390 0 : u32 rbm = 0;
391 :
392 0 : VALIDATE_SW_IF_INDEX (mp);
393 :
394 0 : u32 sw_if_index = ntohl (mp->sw_if_index);
395 0 : u32 flags = ntohl (mp->feature_bitmap);
396 0 : u32 bitmap = 0;
397 :
398 0 : if (flags & L2_LEARN)
399 0 : bitmap |= L2INPUT_FEAT_LEARN;
400 :
401 0 : if (flags & L2_FWD)
402 0 : bitmap |= L2INPUT_FEAT_FWD;
403 :
404 0 : if (flags & L2_FLOOD)
405 0 : bitmap |= L2INPUT_FEAT_FLOOD;
406 :
407 0 : if (flags & L2_UU_FLOOD)
408 0 : bitmap |= L2INPUT_FEAT_UU_FLOOD;
409 :
410 0 : if (flags & L2_ARP_TERM)
411 0 : bitmap |= L2INPUT_FEAT_ARP_TERM;
412 :
413 0 : rbm = l2input_intf_bitmap_enable (sw_if_index, bitmap, mp->is_set);
414 :
415 0 : BAD_SW_IF_INDEX_LABEL;
416 :
417 : /* *INDENT-OFF* */
418 0 : REPLY_MACRO2(VL_API_L2_FLAGS_REPLY,
419 : ({
420 : rmp->resulting_feature_bitmap = ntohl(rbm);
421 : }));
422 : /* *INDENT-ON* */
423 : }
424 :
425 : static void
426 1 : vl_api_bridge_domain_set_default_learn_limit_t_handler (
427 : vl_api_bridge_domain_set_default_learn_limit_t *mp)
428 : {
429 : vl_api_bridge_domain_set_default_learn_limit_reply_t *rmp;
430 1 : int rv = 0;
431 :
432 1 : l2learn_main.bd_default_learn_limit = ntohl (mp->learn_limit);
433 1 : REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_DEFAULT_LEARN_LIMIT_REPLY);
434 : }
435 :
436 : static void
437 1 : vl_api_bridge_domain_set_learn_limit_t_handler (
438 : vl_api_bridge_domain_set_learn_limit_t *mp)
439 : {
440 1 : vlib_main_t *vm = vlib_get_main ();
441 1 : bd_main_t *bdm = &bd_main;
442 : vl_api_bridge_domain_set_learn_limit_reply_t *rmp;
443 1 : int rv = 0;
444 1 : u32 bd_id = ntohl (mp->bd_id);
445 : uword *p;
446 :
447 1 : if (bd_id == 0)
448 : {
449 0 : rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
450 0 : goto out;
451 : }
452 :
453 1 : p = hash_get (bdm->bd_index_by_bd_id, bd_id);
454 1 : if (p == 0)
455 : {
456 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
457 0 : goto out;
458 : }
459 1 : bd_set_learn_limit (vm, *p, ntohl (mp->learn_limit));
460 1 : out:
461 1 : REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_LEARN_LIMIT_REPLY);
462 : }
463 :
464 : static void
465 0 : vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t
466 : * mp)
467 : {
468 0 : vlib_main_t *vm = vlib_get_main ();
469 0 : bd_main_t *bdm = &bd_main;
470 : vl_api_bridge_domain_set_mac_age_reply_t *rmp;
471 0 : int rv = 0;
472 0 : u32 bd_id = ntohl (mp->bd_id);
473 : uword *p;
474 :
475 0 : if (bd_id == 0)
476 : {
477 0 : rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
478 0 : goto out;
479 : }
480 :
481 0 : p = hash_get (bdm->bd_index_by_bd_id, bd_id);
482 0 : if (p == 0)
483 : {
484 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
485 0 : goto out;
486 : }
487 0 : bd_set_mac_age (vm, *p, mp->mac_age);
488 0 : out:
489 0 : REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_MAC_AGE_REPLY);
490 : }
491 :
492 : static void
493 0 : vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp)
494 : {
495 0 : l2_bridge_domain_add_del_args_t a = {
496 0 : .is_add = mp->is_add,
497 0 : .flood = mp->flood,
498 0 : .uu_flood = mp->uu_flood,
499 0 : .forward = mp->forward,
500 0 : .learn = mp->learn,
501 0 : .arp_term = mp->arp_term,
502 0 : .arp_ufwd = mp->arp_ufwd,
503 0 : .mac_age = mp->mac_age,
504 0 : .bd_id = ntohl (mp->bd_id),
505 0 : .bd_tag = mp->bd_tag
506 : };
507 :
508 0 : int rv = bd_add_del (&a);
509 :
510 : vl_api_bridge_domain_add_del_reply_t *rmp;
511 0 : REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY);
512 : }
513 :
514 : static void
515 127 : vl_api_bridge_domain_add_del_v2_t_handler (
516 : vl_api_bridge_domain_add_del_v2_t *mp)
517 : {
518 : vl_api_bridge_domain_add_del_v2_reply_t *rmp;
519 127 : u32 bd_id = ntohl (mp->bd_id);
520 127 : int rv = 0;
521 :
522 127 : if ((~0 == bd_id) && (mp->is_add))
523 17 : bd_id = bd_get_unused_id ();
524 :
525 127 : if ((~0 == bd_id) && (mp->is_add))
526 0 : rv = VNET_API_ERROR_EAGAIN;
527 : else
528 : {
529 127 : l2_bridge_domain_add_del_args_t a = { .is_add = mp->is_add,
530 127 : .flood = mp->flood,
531 127 : .uu_flood = mp->uu_flood,
532 127 : .forward = mp->forward,
533 127 : .learn = mp->learn,
534 127 : .arp_term = mp->arp_term,
535 127 : .arp_ufwd = mp->arp_ufwd,
536 127 : .mac_age = mp->mac_age,
537 : .bd_id = bd_id,
538 127 : .bd_tag = mp->bd_tag };
539 127 : rv = bd_add_del (&a);
540 : }
541 127 : REPLY_MACRO2 (VL_API_BRIDGE_DOMAIN_ADD_DEL_V2_REPLY,
542 : ({ rmp->bd_id = htonl (bd_id); }));
543 : }
544 :
545 : static void
546 81 : send_bridge_domain_details (l2input_main_t * l2im,
547 : vl_api_registration_t * reg,
548 : l2_bridge_domain_t * bd_config,
549 : u32 n_sw_ifs, u32 context)
550 : {
551 : vl_api_bridge_domain_details_t *mp;
552 : l2_flood_member_t *m;
553 : vl_api_bridge_domain_sw_if_t *sw_ifs;
554 : l2_input_config_t *input_cfg;
555 :
556 81 : mp = vl_msg_api_alloc (sizeof (*mp) +
557 81 : (n_sw_ifs * sizeof (vl_api_bridge_domain_sw_if_t)));
558 81 : clib_memset (mp, 0, sizeof (*mp));
559 81 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BRIDGE_DOMAIN_DETAILS);
560 81 : mp->bd_id = ntohl (bd_config->bd_id);
561 81 : mp->flood = bd_feature_flood (bd_config);
562 81 : mp->uu_flood = bd_feature_uu_flood (bd_config);
563 81 : mp->forward = bd_feature_forward (bd_config);
564 81 : mp->learn = bd_feature_learn (bd_config);
565 81 : mp->arp_term = bd_feature_arp_term (bd_config);
566 81 : mp->arp_ufwd = bd_feature_arp_ufwd (bd_config);
567 81 : mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index);
568 81 : mp->uu_fwd_sw_if_index = ntohl (bd_config->uu_fwd_sw_if_index);
569 81 : mp->mac_age = bd_config->mac_age;
570 81 : if (bd_config->bd_tag)
571 : {
572 0 : strncpy ((char *) mp->bd_tag, (char *) bd_config->bd_tag,
573 : ARRAY_LEN (mp->bd_tag) - 1);
574 0 : mp->bd_tag[ARRAY_LEN (mp->bd_tag) - 1] = 0;
575 : }
576 :
577 81 : mp->context = context;
578 :
579 81 : sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details;
580 174 : vec_foreach (m, bd_config->members)
581 : {
582 93 : sw_ifs->sw_if_index = ntohl (m->sw_if_index);
583 93 : input_cfg = vec_elt_at_index (l2im->configs, m->sw_if_index);
584 93 : sw_ifs->shg = input_cfg->shg;
585 93 : sw_ifs++;
586 93 : mp->n_sw_ifs++;
587 : }
588 81 : mp->n_sw_ifs = htonl (mp->n_sw_ifs);
589 :
590 81 : vl_api_send_msg (reg, (u8 *) mp);
591 81 : }
592 :
593 : static void
594 112 : vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp)
595 : {
596 112 : bd_main_t *bdm = &bd_main;
597 112 : l2input_main_t *l2im = &l2input_main;
598 : vl_api_registration_t *reg;
599 : u32 bd_id, bd_index, end, filter_sw_if_index;
600 :
601 112 : reg = vl_api_client_index_to_registration (mp->client_index);
602 112 : if (!reg)
603 0 : return;
604 :
605 112 : filter_sw_if_index = ntohl (mp->sw_if_index);
606 112 : if (filter_sw_if_index != ~0)
607 0 : return; /* UNIMPLEMENTED */
608 :
609 112 : bd_id = ntohl (mp->bd_id);
610 112 : if (bd_id == 0)
611 0 : return;
612 :
613 112 : if (bd_id == ~0)
614 0 : bd_index = 0, end = vec_len (l2im->bd_configs);
615 : else
616 : {
617 112 : bd_index = bd_find_index (bdm, bd_id);
618 112 : if (bd_index == ~0)
619 31 : return;
620 :
621 81 : end = bd_index + 1;
622 : }
623 :
624 162 : for (; bd_index < end; bd_index++)
625 : {
626 : l2_bridge_domain_t *bd_config =
627 81 : l2input_bd_config_from_index (l2im, bd_index);
628 : /* skip placeholder bd_id 0 */
629 81 : if (bd_config && (bd_config->bd_id > 0))
630 81 : send_bridge_domain_details (l2im, reg, bd_config,
631 81 : vec_len (bd_config->members),
632 : mp->context);
633 : }
634 : }
635 :
636 : static bd_flags_t
637 71 : bd_flags_decode (vl_api_bd_flags_t v)
638 : {
639 71 : bd_flags_t f = L2_NONE;
640 :
641 71 : v = ntohl (v);
642 :
643 71 : if (v & BRIDGE_API_FLAG_LEARN)
644 40 : f |= L2_LEARN;
645 71 : if (v & BRIDGE_API_FLAG_FWD)
646 2 : f |= L2_FWD;
647 71 : if (v & BRIDGE_API_FLAG_FLOOD)
648 10 : f |= L2_FLOOD;
649 71 : if (v & BRIDGE_API_FLAG_UU_FLOOD)
650 11 : f |= L2_UU_FLOOD;
651 71 : if (v & BRIDGE_API_FLAG_ARP_TERM)
652 8 : f |= L2_ARP_TERM;
653 71 : if (v & BRIDGE_API_FLAG_ARP_UFWD)
654 0 : f |= L2_ARP_UFWD;
655 :
656 71 : return (f);
657 : }
658 :
659 : static void
660 71 : vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp)
661 : {
662 71 : vlib_main_t *vm = vlib_get_main ();
663 71 : bd_main_t *bdm = &bd_main;
664 : vl_api_bridge_flags_reply_t *rmp;
665 71 : u32 bitmap = 0;
666 71 : int rv = 0;
667 :
668 71 : bd_flags_t flags = bd_flags_decode (mp->flags);
669 71 : u32 bd_id = ntohl (mp->bd_id);
670 71 : if (bd_id == 0)
671 : {
672 0 : rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
673 0 : goto out;
674 : }
675 :
676 71 : u32 bd_index = bd_find_index (bdm, bd_id);
677 71 : if (bd_index == ~0)
678 : {
679 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
680 0 : goto out;
681 : }
682 :
683 71 : bitmap = bd_set_flags (vm, bd_index, flags, mp->is_set);
684 :
685 71 : out:
686 : /* *INDENT-OFF* */
687 71 : REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY,
688 : ({
689 : rmp->resulting_feature_bitmap = ntohl(bitmap);
690 : }));
691 : /* *INDENT-ON* */
692 : }
693 :
694 : static void
695 175 : vl_api_l2_interface_vlan_tag_rewrite_t_handler
696 : (vl_api_l2_interface_vlan_tag_rewrite_t * mp)
697 : {
698 175 : int rv = 0;
699 : vl_api_l2_interface_vlan_tag_rewrite_reply_t *rmp;
700 175 : vnet_main_t *vnm = vnet_get_main ();
701 175 : vlib_main_t *vm = vlib_get_main ();
702 : u32 vtr_op;
703 :
704 175 : VALIDATE_SW_IF_INDEX (mp);
705 :
706 175 : vtr_op = ntohl (mp->vtr_op);
707 :
708 : /* The L2 code is unsuspicious */
709 175 : switch (vtr_op)
710 : {
711 175 : case L2_VTR_DISABLED:
712 : case L2_VTR_PUSH_1:
713 : case L2_VTR_PUSH_2:
714 : case L2_VTR_POP_1:
715 : case L2_VTR_POP_2:
716 : case L2_VTR_TRANSLATE_1_1:
717 : case L2_VTR_TRANSLATE_1_2:
718 : case L2_VTR_TRANSLATE_2_1:
719 : case L2_VTR_TRANSLATE_2_2:
720 175 : break;
721 :
722 0 : default:
723 0 : rv = VNET_API_ERROR_INVALID_VALUE;
724 0 : goto bad_sw_if_index;
725 : }
726 :
727 175 : rv = l2vtr_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
728 : ntohl (mp->push_dot1q), ntohl (mp->tag1),
729 : ntohl (mp->tag2));
730 :
731 175 : BAD_SW_IF_INDEX_LABEL;
732 :
733 175 : REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY);
734 : }
735 :
736 : static void
737 0 : vl_api_l2_interface_pbb_tag_rewrite_t_handler
738 : (vl_api_l2_interface_pbb_tag_rewrite_t * mp)
739 : {
740 : vl_api_l2_interface_pbb_tag_rewrite_reply_t *rmp;
741 0 : vnet_main_t *vnm = vnet_get_main ();
742 0 : vlib_main_t *vm = vlib_get_main ();
743 : u32 vtr_op;
744 0 : int rv = 0;
745 : mac_address_t b_dmac, b_smac;
746 :
747 0 : VALIDATE_SW_IF_INDEX (mp);
748 :
749 0 : vtr_op = ntohl (mp->vtr_op);
750 :
751 0 : switch (vtr_op)
752 : {
753 0 : case L2_VTR_DISABLED:
754 : case L2_VTR_PUSH_2:
755 : case L2_VTR_POP_2:
756 : case L2_VTR_TRANSLATE_2_1:
757 0 : break;
758 :
759 0 : default:
760 0 : rv = VNET_API_ERROR_INVALID_VALUE;
761 0 : goto bad_sw_if_index;
762 : }
763 :
764 0 : mac_address_decode (mp->b_dmac, &b_dmac);
765 0 : mac_address_decode (mp->b_smac, &b_smac);
766 :
767 0 : rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
768 0 : b_dmac.bytes, b_smac.bytes, ntohs (mp->b_vlanid),
769 0 : ntohl (mp->i_sid), ntohs (mp->outer_tag));
770 :
771 0 : BAD_SW_IF_INDEX_LABEL;
772 :
773 0 : REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY);
774 : }
775 :
776 : static void
777 82 : vl_api_sw_interface_set_l2_xconnect_t_handler
778 : (vl_api_sw_interface_set_l2_xconnect_t * mp)
779 : {
780 : vl_api_sw_interface_set_l2_xconnect_reply_t *rmp;
781 82 : int rv = 0;
782 82 : u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
783 82 : u32 tx_sw_if_index = ntohl (mp->tx_sw_if_index);
784 82 : vlib_main_t *vm = vlib_get_main ();
785 82 : vnet_main_t *vnm = vnet_get_main ();
786 :
787 82 : VALIDATE_RX_SW_IF_INDEX (mp);
788 :
789 82 : if (mp->enable)
790 : {
791 48 : VALIDATE_TX_SW_IF_INDEX (mp);
792 48 : rv = set_int_l2_mode (vm, vnm, MODE_L2_XC,
793 : rx_sw_if_index, 0,
794 : L2_BD_PORT_TYPE_NORMAL, 0, tx_sw_if_index);
795 : }
796 : else
797 : {
798 34 : rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0,
799 : L2_BD_PORT_TYPE_NORMAL, 0, 0);
800 : }
801 :
802 82 : switch (rv)
803 : {
804 0 : case MODE_ERROR_ETH:
805 0 : rv = VNET_API_ERROR_NON_ETHERNET;
806 0 : break;
807 0 : case MODE_ERROR_BVI_DEF:
808 0 : rv = VNET_API_ERROR_BD_ALREADY_HAS_BVI;
809 0 : break;
810 : }
811 :
812 82 : BAD_RX_SW_IF_INDEX_LABEL;
813 82 : BAD_TX_SW_IF_INDEX_LABEL;
814 :
815 82 : REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_XCONNECT_REPLY);
816 : }
817 :
818 : static int
819 1438 : l2_bd_port_type_decode (vl_api_l2_port_type_t v, l2_bd_port_type_t * l)
820 : {
821 1438 : v = clib_net_to_host_u32 (v);
822 :
823 1438 : switch (v)
824 : {
825 1421 : case L2_API_PORT_TYPE_NORMAL:
826 1421 : *l = L2_BD_PORT_TYPE_NORMAL;
827 1421 : return 0;
828 13 : case L2_API_PORT_TYPE_BVI:
829 13 : *l = L2_BD_PORT_TYPE_BVI;
830 13 : return 0;
831 4 : case L2_API_PORT_TYPE_UU_FWD:
832 4 : *l = L2_BD_PORT_TYPE_UU_FWD;
833 4 : return 0;
834 : }
835 :
836 0 : return (VNET_API_ERROR_INVALID_VALUE);
837 : }
838 :
839 : static void
840 1438 : vl_api_sw_interface_set_l2_bridge_t_handler
841 : (vl_api_sw_interface_set_l2_bridge_t * mp)
842 : {
843 1438 : bd_main_t *bdm = &bd_main;
844 : vl_api_sw_interface_set_l2_bridge_reply_t *rmp;
845 1438 : int rv = 0;
846 1438 : vlib_main_t *vm = vlib_get_main ();
847 1438 : vnet_main_t *vnm = vnet_get_main ();
848 : l2_bd_port_type_t pt;
849 :
850 1438 : VALIDATE_RX_SW_IF_INDEX (mp);
851 1438 : u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
852 1438 : rv = l2_bd_port_type_decode (mp->port_type, &pt);
853 :
854 1438 : if (0 != rv)
855 0 : goto out;
856 1438 : if (mp->enable)
857 : {
858 1256 : VALIDATE_BD_ID (mp);
859 1256 : u32 bd_id = ntohl (mp->bd_id);
860 1256 : u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id);
861 :
862 1256 : rv = set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE,
863 1256 : rx_sw_if_index, bd_index, pt, mp->shg, 0);
864 : }
865 : else
866 : {
867 182 : rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0, pt, 0, 0);
868 : }
869 :
870 1438 : switch (rv)
871 : {
872 0 : case MODE_ERROR_ETH:
873 0 : rv = VNET_API_ERROR_NON_ETHERNET;
874 0 : break;
875 0 : case MODE_ERROR_BVI_DEF:
876 0 : rv = VNET_API_ERROR_BD_ALREADY_HAS_BVI;
877 0 : break;
878 : }
879 :
880 1438 : BAD_RX_SW_IF_INDEX_LABEL;
881 1438 : BAD_BD_ID_LABEL;
882 1438 : out:
883 1438 : REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY);
884 : }
885 :
886 : static void
887 0 : send_bd_ip_mac_entry (vpe_api_main_t * am,
888 : vl_api_registration_t * reg,
889 : u32 bd_id,
890 : const ip46_address_t * ip,
891 : ip46_type_t itype,
892 : const mac_address_t * mac, u32 context)
893 : {
894 : vl_api_bd_ip_mac_details_t *mp;
895 :
896 0 : mp = vl_msg_api_alloc (sizeof (*mp));
897 0 : clib_memset (mp, 0, sizeof (*mp));
898 0 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BD_IP_MAC_DETAILS);
899 :
900 0 : mp->context = context;
901 0 : mp->entry.bd_id = ntohl (bd_id);
902 :
903 0 : ip_address_encode (ip, itype, &mp->entry.ip);
904 0 : mac_address_encode (mac, mp->entry.mac);
905 :
906 0 : vl_api_send_msg (reg, (u8 *) mp);
907 0 : }
908 :
909 : static void
910 0 : vl_api_bd_ip_mac_dump_t_handler (vl_api_bd_ip_mac_dump_t * mp)
911 : {
912 0 : vpe_api_main_t *am = &vpe_api_main;
913 0 : bd_main_t *bdm = &bd_main;
914 : l2_bridge_domain_t *bd_config;
915 0 : u32 bd_id = ntohl (mp->bd_id);
916 : u32 bd_index, start, end;
917 : vl_api_registration_t *reg;
918 : uword *p;
919 :
920 0 : reg = vl_api_client_index_to_registration (mp->client_index);
921 0 : if (!reg)
922 0 : return;
923 :
924 : /* see bd_id: ~0 means "any" */
925 0 : if (bd_id == ~0)
926 : {
927 0 : start = 1;
928 0 : end = vec_len (l2input_main.bd_configs);
929 : }
930 : else
931 : {
932 0 : p = hash_get (bdm->bd_index_by_bd_id, bd_id);
933 0 : if (p == 0)
934 0 : return;
935 :
936 0 : bd_index = p[0];
937 0 : vec_validate (l2input_main.bd_configs, bd_index);
938 0 : start = bd_index;
939 0 : end = start + 1;
940 : }
941 :
942 0 : for (bd_index = start; bd_index < end; bd_index++)
943 : {
944 0 : bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
945 0 : if (bd_is_valid (bd_config))
946 : {
947 : ip4_address_t ip4_addr;
948 : ip6_address_t *ip6_addr;
949 : mac_address_t mac;
950 : u64 mac64;
951 0 : bd_id = bd_config->bd_id;
952 :
953 : /* *INDENT-OFF* */
954 0 : hash_foreach (ip4_addr.as_u32, mac64, bd_config->mac_by_ip4,
955 : ({
956 : ip46_address_t ip = {
957 : .ip4 = ip4_addr,
958 : };
959 : mac_address_from_u64(&mac, mac64);
960 :
961 : send_bd_ip_mac_entry (am, reg, bd_id, &ip, IP46_TYPE_IP4,
962 : &mac, mp->context);
963 : }));
964 :
965 0 : hash_foreach_mem (ip6_addr, mac64, bd_config->mac_by_ip6,
966 : ({
967 : ip46_address_t ip = {
968 : .ip6 = *ip6_addr,
969 : };
970 : mac_address_from_u64(&mac, mac64);
971 :
972 : send_bd_ip_mac_entry (am, reg, bd_id, &ip, IP46_TYPE_IP6,
973 : &mac, mp->context);
974 : }));
975 : /* *INDENT-ON* */
976 : }
977 : }
978 : }
979 :
980 : static void
981 85 : vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp)
982 : {
983 85 : ip46_address_t ip_addr = ip46_address_initializer;
984 : vl_api_bd_ip_mac_add_del_reply_t *rmp;
985 85 : bd_main_t *bdm = &bd_main;
986 : u32 bd_index, bd_id;
987 : mac_address_t mac;
988 : ip46_type_t type;
989 85 : int rv = 0;
990 : uword *p;
991 :
992 85 : bd_id = ntohl (mp->entry.bd_id);
993 :
994 85 : if (bd_id == 0)
995 : {
996 0 : rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
997 0 : goto out;
998 : }
999 :
1000 85 : p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1001 85 : if (p == 0)
1002 : {
1003 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1004 0 : goto out;
1005 : }
1006 85 : bd_index = p[0];
1007 :
1008 85 : type = ip_address_decode (&mp->entry.ip, &ip_addr);
1009 85 : mac_address_decode (mp->entry.mac, &mac);
1010 :
1011 85 : if (bd_add_del_ip_mac (bd_index, type, &ip_addr, &mac, mp->is_add))
1012 0 : rv = VNET_API_ERROR_UNSPECIFIED;
1013 :
1014 85 : out:
1015 85 : REPLY_MACRO (VL_API_BD_IP_MAC_ADD_DEL_REPLY);
1016 : }
1017 :
1018 : static void
1019 0 : vl_api_bd_ip_mac_flush_t_handler (vl_api_bd_ip_mac_flush_t * mp)
1020 : {
1021 : vl_api_bd_ip_mac_flush_reply_t *rmp;
1022 0 : bd_main_t *bdm = &bd_main;
1023 : u32 bd_index, bd_id;
1024 0 : int rv = 0;
1025 : uword *p;
1026 :
1027 0 : bd_id = ntohl (mp->bd_id);
1028 :
1029 0 : if (bd_id == 0)
1030 : {
1031 0 : rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
1032 0 : goto out;
1033 : }
1034 :
1035 0 : p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1036 0 : if (p == 0)
1037 : {
1038 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1039 0 : goto out;
1040 : }
1041 0 : bd_index = p[0];
1042 :
1043 0 : bd_flush_ip_mac (bd_index);
1044 :
1045 0 : out:
1046 0 : REPLY_MACRO (VL_API_BD_IP_MAC_FLUSH_REPLY);
1047 : }
1048 :
1049 : extern void l2_efp_filter_configure (vnet_main_t * vnet_main,
1050 : u32 sw_if_index, u8 enable);
1051 :
1052 : static void
1053 0 : vl_api_l2_interface_efp_filter_t_handler (vl_api_l2_interface_efp_filter_t *
1054 : mp)
1055 : {
1056 : int rv;
1057 : vl_api_l2_interface_efp_filter_reply_t *rmp;
1058 0 : vnet_main_t *vnm = vnet_get_main ();
1059 :
1060 0 : VALIDATE_SW_IF_INDEX (mp);
1061 :
1062 : // enable/disable the feature
1063 0 : l2_efp_filter_configure (vnm, ntohl (mp->sw_if_index), mp->enable_disable);
1064 0 : rv = vnm->api_errno;
1065 :
1066 0 : BAD_SW_IF_INDEX_LABEL;
1067 0 : REPLY_MACRO (VL_API_L2_INTERFACE_EFP_FILTER_REPLY);
1068 : }
1069 :
1070 : static void
1071 0 : vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp)
1072 : {
1073 : extern int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
1074 : int is_add);
1075 : vl_api_l2_patch_add_del_reply_t *rmp;
1076 : int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
1077 : int is_add);
1078 0 : int rv = 0;
1079 :
1080 0 : VALIDATE_RX_SW_IF_INDEX (mp);
1081 0 : VALIDATE_TX_SW_IF_INDEX (mp);
1082 :
1083 0 : rv = vnet_l2_patch_add_del (ntohl (mp->rx_sw_if_index),
1084 : ntohl (mp->tx_sw_if_index),
1085 0 : (int) (mp->is_add != 0));
1086 :
1087 0 : BAD_RX_SW_IF_INDEX_LABEL;
1088 0 : BAD_TX_SW_IF_INDEX_LABEL;
1089 :
1090 0 : REPLY_MACRO (VL_API_L2_PATCH_ADD_DEL_REPLY);
1091 : }
1092 :
1093 : static void
1094 0 : vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t * mp)
1095 : {
1096 : vl_api_sw_interface_set_vpath_reply_t *rmp;
1097 0 : int rv = 0;
1098 0 : u32 sw_if_index = ntohl (mp->sw_if_index);
1099 :
1100 0 : VALIDATE_SW_IF_INDEX (mp);
1101 :
1102 0 : l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VPATH, mp->enable);
1103 0 : vnet_feature_enable_disable ("ip4-unicast", "vpath-input-ip4",
1104 0 : sw_if_index, mp->enable, 0, 0);
1105 0 : vnet_feature_enable_disable ("ip4-multicast", "vpath-input-ip4",
1106 0 : sw_if_index, mp->enable, 0, 0);
1107 0 : vnet_feature_enable_disable ("ip6-unicast", "vpath-input-ip6",
1108 0 : sw_if_index, mp->enable, 0, 0);
1109 0 : vnet_feature_enable_disable ("ip6-multicast", "vpath-input-ip6",
1110 0 : sw_if_index, mp->enable, 0, 0);
1111 :
1112 0 : BAD_SW_IF_INDEX_LABEL;
1113 :
1114 0 : REPLY_MACRO (VL_API_SW_INTERFACE_SET_VPATH_REPLY);
1115 : }
1116 :
1117 : static void
1118 4 : vl_api_bvi_create_t_handler (vl_api_bvi_create_t * mp)
1119 : {
1120 : vl_api_bvi_create_reply_t *rmp;
1121 : mac_address_t mac;
1122 : u32 sw_if_index;
1123 : int rv;
1124 :
1125 4 : mac_address_decode (mp->mac, &mac);
1126 :
1127 4 : rv = l2_bvi_create (ntohl (mp->user_instance), &mac, &sw_if_index);
1128 :
1129 : /* *INDENT-OFF* */
1130 4 : REPLY_MACRO2(VL_API_BVI_CREATE_REPLY,
1131 : ({
1132 : rmp->sw_if_index = ntohl (sw_if_index);
1133 : }));
1134 : /* *INDENT-ON* */
1135 : }
1136 :
1137 : static void
1138 0 : vl_api_bvi_delete_t_handler (vl_api_bvi_delete_t * mp)
1139 : {
1140 : vl_api_bvi_delete_reply_t *rmp;
1141 : int rv;
1142 :
1143 0 : rv = l2_bvi_delete (ntohl (mp->sw_if_index));
1144 :
1145 0 : REPLY_MACRO (VL_API_BVI_DELETE_REPLY);
1146 : }
1147 :
1148 : static bool
1149 20 : l2_arp_term_publish_event_is_equal (const l2_arp_term_publish_event_t * e1,
1150 : const l2_arp_term_publish_event_t * e2)
1151 : {
1152 20 : if (e1 == NULL || e2 == NULL)
1153 0 : return false;
1154 20 : return (ip46_address_is_equal (&e1->ip, &e2->ip) &&
1155 28 : (e1->sw_if_index == e2->sw_if_index) &&
1156 8 : (mac_address_equal (&e1->mac, &e2->mac)));
1157 : }
1158 :
1159 : static uword
1160 575 : l2_arp_term_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
1161 : vlib_frame_t * f)
1162 : {
1163 : /* These cross the longjmp boundary (vlib_process_wait_for_event)
1164 : * and need to be volatile - to prevent them from being optimized into
1165 : * a register - which could change during suspension */
1166 575 : volatile f64 last = vlib_time_now (vm);
1167 575 : volatile l2_arp_term_publish_event_t last_event = { };
1168 :
1169 575 : l2_arp_term_main_t *l2am = &l2_arp_term_main;
1170 :
1171 : while (1)
1172 4 : {
1173 579 : uword event_type = L2_ARP_TERM_EVENT_PUBLISH;
1174 : vpe_client_registration_t *reg;
1175 : f64 now;
1176 :
1177 579 : vlib_process_wait_for_event (vm);
1178 :
1179 4 : vlib_process_get_event_data (vm, &event_type);
1180 4 : now = vlib_time_now (vm);
1181 :
1182 4 : if (event_type == L2_ARP_TERM_EVENT_PUBLISH)
1183 : {
1184 : l2_arp_term_publish_event_t *event;
1185 :
1186 24 : vec_foreach (event, l2am->publish_events)
1187 : {
1188 : /* dampen duplicate events - cast away volatile */
1189 20 : if (l2_arp_term_publish_event_is_equal
1190 8 : (event, (l2_arp_term_publish_event_t *) & last_event) &&
1191 8 : (now - last) < 10.0)
1192 : {
1193 8 : continue;
1194 : }
1195 12 : last_event = *event;
1196 12 : last = now;
1197 :
1198 24 : pool_foreach (reg, vpe_api_main.l2_arp_term_events_registrations)
1199 : {
1200 : vl_api_registration_t *vl_reg;
1201 : vl_reg =
1202 12 : vl_api_client_index_to_registration (reg->client_index);
1203 12 : ALWAYS_ASSERT (vl_reg != NULL);
1204 :
1205 12 : if (vl_reg && vl_api_can_send_msg (vl_reg))
1206 : {
1207 : vl_api_l2_arp_term_event_t *vevent;
1208 12 : vevent = vl_msg_api_alloc (sizeof *vevent);
1209 12 : clib_memset (vevent, 0, sizeof *vevent);
1210 12 : vevent->_vl_msg_id =
1211 12 : htons (REPLY_MSG_ID_BASE + VL_API_L2_ARP_TERM_EVENT);
1212 12 : vevent->client_index = reg->client_index;
1213 12 : vevent->pid = reg->client_pid;
1214 12 : ip_address_encode (&event->ip, event->type, &vevent->ip);
1215 12 : vevent->sw_if_index = htonl (event->sw_if_index);
1216 12 : mac_address_encode (&event->mac, vevent->mac);
1217 12 : vl_api_send_msg (vl_reg, (u8 *) vevent);
1218 : }
1219 : }
1220 : }
1221 4 : vec_reset_length (l2am->publish_events);
1222 : }
1223 : }
1224 :
1225 : return 0;
1226 : }
1227 :
1228 : /* *INDENT-OFF* */
1229 183788 : VLIB_REGISTER_NODE (l2_arp_term_process_node) = {
1230 : .function = l2_arp_term_process,
1231 : .type = VLIB_NODE_TYPE_PROCESS,
1232 : .name = "l2-arp-term-publisher",
1233 : };
1234 : /* *INDENT-ON* */
1235 :
1236 : static void
1237 4 : vl_api_want_l2_arp_term_events_t_handler (vl_api_want_l2_arp_term_events_t *
1238 : mp)
1239 : {
1240 : vl_api_want_l2_arp_term_events_reply_t *rmp;
1241 4 : vpe_api_main_t *am = &vpe_api_main;
1242 : vpe_client_registration_t *rp;
1243 4 : int rv = 0;
1244 : uword *p;
1245 :
1246 4 : p = hash_get (am->l2_arp_term_events_registration_hash, mp->client_index);
1247 :
1248 4 : if (p)
1249 : {
1250 2 : if (mp->enable)
1251 : {
1252 0 : clib_warning ("pid %d: already enabled...", mp->pid);
1253 0 : rv = VNET_API_ERROR_INVALID_REGISTRATION;
1254 0 : goto reply;
1255 : }
1256 : else
1257 : {
1258 2 : rp = pool_elt_at_index (am->l2_arp_term_events_registrations, p[0]);
1259 2 : pool_put (am->l2_arp_term_events_registrations, rp);
1260 2 : hash_unset (am->l2_arp_term_events_registration_hash,
1261 : mp->client_index);
1262 2 : if (pool_elts (am->l2_arp_term_events_registrations) == 0)
1263 2 : l2_arp_term_set_publisher_node (false);
1264 2 : goto reply;
1265 : }
1266 : }
1267 2 : if (mp->enable == 0)
1268 : {
1269 0 : clib_warning ("pid %d: already disabled...", mp->pid);
1270 0 : rv = VNET_API_ERROR_INVALID_REGISTRATION;
1271 0 : goto reply;
1272 : }
1273 2 : pool_get (am->l2_arp_term_events_registrations, rp);
1274 2 : rp->client_index = mp->client_index;
1275 2 : rp->client_pid = mp->pid;
1276 2 : hash_set (am->l2_arp_term_events_registration_hash, rp->client_index,
1277 : rp - am->l2_arp_term_events_registrations);
1278 2 : l2_arp_term_set_publisher_node (true);
1279 :
1280 4 : reply:
1281 4 : REPLY_MACRO (VL_API_WANT_L2_ARP_TERM_EVENTS_REPLY);
1282 : }
1283 :
1284 : static clib_error_t *
1285 1241 : want_l2_arp_term_events_reaper (u32 client_index)
1286 : {
1287 : vpe_client_registration_t *rp;
1288 : vpe_api_main_t *am;
1289 : uword *p;
1290 :
1291 1241 : am = &vpe_api_main;
1292 :
1293 : /* remove from the registration hash */
1294 1241 : p = hash_get (am->l2_arp_term_events_registration_hash, client_index);
1295 :
1296 1241 : if (p)
1297 : {
1298 0 : rp = pool_elt_at_index (am->l2_arp_term_events_registrations, p[0]);
1299 0 : pool_put (am->l2_arp_term_events_registrations, rp);
1300 0 : hash_unset (am->l2_arp_term_events_registration_hash, client_index);
1301 0 : if (pool_elts (am->l2_arp_term_events_registrations) == 0)
1302 0 : l2_arp_term_set_publisher_node (false);
1303 : }
1304 1241 : return (NULL);
1305 : }
1306 :
1307 575 : VL_MSG_API_REAPER_FUNCTION (want_l2_arp_term_events_reaper);
1308 :
1309 : #include <vnet/l2/l2.api.c>
1310 : static clib_error_t *
1311 575 : l2_api_hookup (vlib_main_t * vm)
1312 : {
1313 575 : api_main_t *am = vlibapi_get_main ();
1314 :
1315 : /*
1316 : * Set up the (msg_name, crc, message-id) table
1317 : */
1318 575 : REPLY_MSG_ID_BASE = setup_message_id_table ();
1319 :
1320 : /* Mark VL_API_BRIDGE_DOMAIN_DUMP as mp safe */
1321 575 : vl_api_set_msg_thread_safe (
1322 575 : am, REPLY_MSG_ID_BASE + VL_API_BRIDGE_DOMAIN_DUMP, 1);
1323 :
1324 575 : return 0;
1325 : }
1326 :
1327 3455 : VLIB_API_INIT_FUNCTION (l2_api_hookup);
1328 :
1329 : /*
1330 : * fd.io coding-style-patch-verification: ON
1331 : *
1332 : * Local Variables:
1333 : * eval: (c-set-style "gnu")
1334 : * End:
1335 : */
|