l2: Add bridge_domain_add_del_v2 to l2 api
[vpp.git] / src / vnet / l2 / l2_api.c
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 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   mp = vl_msg_api_alloc (sizeof (*mp));
50   clib_memset (mp, 0, sizeof (*mp));
51   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_L2_XCONNECT_DETAILS);
52   mp->context = context;
53   mp->rx_sw_if_index = htonl (rx_sw_if_index);
54   mp->tx_sw_if_index = htonl (tx_sw_if_index);
55
56   vl_api_send_msg (reg, (u8 *) mp);
57 }
58
59 static void
60 vl_api_l2_xconnect_dump_t_handler (vl_api_l2_xconnect_dump_t * mp)
61 {
62   vl_api_registration_t *reg;
63   l2input_main_t *l2im = &l2input_main;
64   u32 sw_if_index;
65   l2_input_config_t *config;
66
67   reg = vl_api_client_index_to_registration (mp->client_index);
68   if (!reg)
69     return;
70
71   /* *INDENT-OFF* */
72   vec_foreach_index (sw_if_index, l2im->configs)
73     {
74       config = vec_elt_at_index (l2im->configs, sw_if_index);
75       if (l2_input_is_xconnect (config))
76         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 vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp)
84 {
85   int rv = 0;
86   vl_api_l2_fib_clear_table_reply_t *rmp;
87
88   /* Clear all MACs including static MACs  */
89   l2fib_clear_table ();
90
91   REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY);
92 }
93
94 static void
95 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   mp = vl_msg_api_alloc (sizeof (*mp));
103   clib_memset (mp, 0, sizeof (*mp));
104   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_L2_FIB_TABLE_DETAILS);
105
106   mp->bd_id =
107     ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id);
108
109   mac_address_encode ((mac_address_t *) l2fe_key->fields.mac, mp->mac);
110   mp->sw_if_index = ntohl (l2fe_res->fields.sw_if_index);
111   mp->static_mac = (l2fib_entry_result_is_set_STATIC (l2fe_res) ? 1 : 0);
112   mp->filter_mac = (l2fib_entry_result_is_set_FILTER (l2fe_res) ? 1 : 0);
113   mp->bvi_mac = (l2fib_entry_result_is_set_BVI (l2fe_res) ? 1 : 0);
114   mp->context = context;
115
116   vl_api_send_msg (reg, (u8 *) mp);
117 }
118
119 static void
120 vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp)
121 {
122   vpe_api_main_t *am = &vpe_api_main;
123   bd_main_t *bdm = &bd_main;
124   l2fib_entry_key_t *l2fe_key = NULL;
125   l2fib_entry_result_t *l2fe_res = NULL;
126   u32 ni, bd_id = ntohl (mp->bd_id);
127   u32 bd_index;
128   vl_api_registration_t *reg;
129   uword *p;
130
131   reg = vl_api_client_index_to_registration (mp->client_index);
132   if (!reg)
133     return;
134
135   /* see l2fib_table_dump: ~0 means "any" */
136   if (bd_id == ~0)
137     bd_index = ~0;
138   else
139     {
140       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
141       if (p == 0)
142         return;
143
144       bd_index = p[0];
145     }
146
147   l2fib_table_dump (bd_index, &l2fe_key, &l2fe_res);
148
149   vec_foreach_index (ni, l2fe_key)
150   {
151     send_l2fib_table_entry (am, reg, vec_elt_at_index (l2fe_key, ni),
152                             vec_elt_at_index (l2fe_res, ni), mp->context);
153   }
154   vec_free (l2fe_key);
155   vec_free (l2fe_res);
156 }
157
158 static void
159 vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp)
160 {
161   bd_main_t *bdm = &bd_main;
162   l2input_main_t *l2im = &l2input_main;
163   vl_api_l2fib_add_del_reply_t *rmp;
164   int rv = 0;
165   u32 bd_id = ntohl (mp->bd_id);
166   uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
167
168   if (!p)
169     {
170       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
171       goto bad_sw_if_index;
172     }
173   u32 bd_index = p[0];
174
175   mac_address_t mac;
176
177   mac_address_decode (mp->mac, &mac);
178   if (mp->is_add)
179     {
180       if (mp->filter_mac)
181         l2fib_add_filter_entry (mac.bytes, bd_index);
182       else
183         {
184           l2fib_entry_result_flags_t flags = L2FIB_ENTRY_RESULT_FLAG_NONE;
185           u32 sw_if_index = ntohl (mp->sw_if_index);
186           VALIDATE_SW_IF_INDEX (mp);
187           if (vec_len (l2im->configs) <= sw_if_index)
188             {
189               rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
190               goto bad_sw_if_index;
191             }
192           else
193             {
194               l2_input_config_t *config;
195               config = vec_elt_at_index (l2im->configs, sw_if_index);
196               if (!l2_input_is_bridge (config))
197                 {
198                   rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
199                   goto bad_sw_if_index;
200                 }
201             }
202           if (mp->static_mac)
203             flags |= L2FIB_ENTRY_RESULT_FLAG_STATIC;
204           if (mp->bvi_mac)
205             flags |= L2FIB_ENTRY_RESULT_FLAG_BVI;
206           l2fib_add_entry (mac.bytes, bd_index, sw_if_index, flags);
207         }
208     }
209   else
210     {
211       u32 sw_if_index = ntohl (mp->sw_if_index);
212       if (l2fib_del_entry (mac.bytes, bd_index, sw_if_index))
213         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
214     }
215
216   BAD_SW_IF_INDEX_LABEL;
217
218   REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY);
219 }
220
221 static void
222 vl_api_want_l2_macs_events2_t_handler (vl_api_want_l2_macs_events2_t *mp)
223 {
224   int rv = 0;
225   vl_api_want_l2_macs_events2_reply_t *rmp;
226   l2learn_main_t *lm = &l2learn_main;
227   l2fib_main_t *fm = &l2fib_main;
228   u32 pid = ntohl (mp->pid);
229
230   if (mp->enable_disable)
231     {
232       if ((lm->client_pid == 0) || (lm->client_pid == pid))
233         {
234           if (mp->max_macs_in_event)
235             fm->max_macs_in_event = mp->max_macs_in_event * 10;
236           else
237             {
238               rv = VNET_API_ERROR_INVALID_VALUE;
239               goto exit;
240             }
241
242           /* if scan_delay was not set before */
243           if (fm->event_scan_delay == 0.0)
244             fm->event_scan_delay = (f64) (10) * 10e-3;
245
246           lm->client_pid = pid;
247           lm->client_index = mp->client_index;
248           l2fib_flush_all_mac (vlib_get_main ());
249         }
250       else if (lm->client_pid != pid)
251         {
252           rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT;
253           goto exit;
254         }
255     }
256   else if (lm->client_pid)
257     {
258       lm->client_pid = 0;
259       lm->client_index = 0;
260     }
261
262 exit:
263   REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS2_REPLY);
264 }
265
266 static void
267 vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t *mp)
268 {
269   int rv = 0;
270   vl_api_want_l2_macs_events_reply_t *rmp;
271   l2learn_main_t *lm = &l2learn_main;
272   l2fib_main_t *fm = &l2fib_main;
273   u32 pid = ntohl (mp->pid);
274   u32 learn_limit = ntohl (mp->learn_limit);
275
276   if (mp->enable_disable)
277     {
278       if ((lm->client_pid == 0) || (lm->client_pid == pid))
279         {
280           if ((mp->max_macs_in_event == 0) || (mp->scan_delay == 0) ||
281               (learn_limit == 0) || (learn_limit > L2LEARN_DEFAULT_LIMIT))
282             {
283               rv = VNET_API_ERROR_INVALID_VALUE;
284               goto exit;
285             }
286           lm->client_pid = pid;
287           lm->client_index = mp->client_index;
288
289           fm->max_macs_in_event = mp->max_macs_in_event * 10;
290           fm->event_scan_delay = (f64) (mp->scan_delay) * 10e-3;
291
292           /* change learn limit and flush all learned MACs */
293           lm->global_learn_limit = learn_limit;
294           l2fib_flush_all_mac (vlib_get_main ());
295         }
296       else if (lm->client_pid != pid)
297         {
298           rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT;
299           goto exit;
300         }
301     }
302   else if (lm->client_pid)
303     {
304       lm->client_pid = 0;
305       lm->client_index = 0;
306       if (learn_limit && (learn_limit <= L2LEARN_DEFAULT_LIMIT))
307         lm->global_learn_limit = learn_limit;
308       else
309         lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT;
310     }
311
312 exit:
313   REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS_REPLY);
314 }
315
316 static void
317 vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp)
318 {
319   int rv = 0;
320   vlib_main_t *vm = vlib_get_main ();
321   vl_api_l2fib_flush_int_reply_t *rmp;
322
323   VALIDATE_SW_IF_INDEX (mp);
324
325   u32 sw_if_index = ntohl (mp->sw_if_index);
326   l2fib_flush_int_mac (vm, sw_if_index);
327
328   BAD_SW_IF_INDEX_LABEL;
329   REPLY_MACRO (VL_API_L2FIB_FLUSH_INT_REPLY);
330 }
331
332 static void
333 vl_api_l2fib_flush_all_t_handler (vl_api_l2fib_flush_all_t * mp)
334 {
335   int rv = 0;
336   vl_api_l2fib_flush_all_reply_t *rmp;
337
338   l2fib_flush_all_mac (vlib_get_main ());
339   REPLY_MACRO (VL_API_L2FIB_FLUSH_ALL_REPLY);
340 }
341
342 static void
343 vl_api_l2fib_flush_bd_t_handler (vl_api_l2fib_flush_bd_t * mp)
344 {
345   int rv = 0;
346   vlib_main_t *vm = vlib_get_main ();
347   bd_main_t *bdm = &bd_main;
348   vl_api_l2fib_flush_bd_reply_t *rmp;
349
350   u32 bd_id = ntohl (mp->bd_id);
351   uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
352   if (p == 0)
353     {
354       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
355       goto out;
356     }
357   l2fib_flush_bd_mac (vm, *p);
358 out:
359   REPLY_MACRO (VL_API_L2FIB_FLUSH_BD_REPLY);
360 }
361
362 static void
363 vl_api_l2fib_set_scan_delay_t_handler (vl_api_l2fib_set_scan_delay_t *mp)
364 {
365   int rv = 0;
366   l2fib_main_t *fm = &l2fib_main;
367   vl_api_l2fib_set_scan_delay_reply_t *rmp;
368   u16 scan_delay = ntohs (mp->scan_delay);
369
370   if (mp->scan_delay)
371     {
372       fm->event_scan_delay = (f64) (scan_delay) *10e-3;
373       l2fib_flush_all_mac (vlib_get_main ());
374     }
375   else
376     {
377       rv = VNET_API_ERROR_INVALID_VALUE;
378       goto exit;
379     }
380
381 exit:
382   REPLY_MACRO (VL_API_L2FIB_SET_SCAN_DELAY_REPLY);
383 }
384
385 static void
386 vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp)
387 {
388   vl_api_l2_flags_reply_t *rmp;
389   int rv = 0;
390   u32 rbm = 0;
391
392   VALIDATE_SW_IF_INDEX (mp);
393
394   u32 sw_if_index = ntohl (mp->sw_if_index);
395   u32 flags = ntohl (mp->feature_bitmap);
396   u32 bitmap = 0;
397
398   if (flags & L2_LEARN)
399     bitmap |= L2INPUT_FEAT_LEARN;
400
401   if (flags & L2_FWD)
402     bitmap |= L2INPUT_FEAT_FWD;
403
404   if (flags & L2_FLOOD)
405     bitmap |= L2INPUT_FEAT_FLOOD;
406
407   if (flags & L2_UU_FLOOD)
408     bitmap |= L2INPUT_FEAT_UU_FLOOD;
409
410   if (flags & L2_ARP_TERM)
411     bitmap |= L2INPUT_FEAT_ARP_TERM;
412
413   rbm = l2input_intf_bitmap_enable (sw_if_index, bitmap, mp->is_set);
414
415   BAD_SW_IF_INDEX_LABEL;
416
417   /* *INDENT-OFF* */
418   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 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   int rv = 0;
431
432   l2learn_main.bd_default_learn_limit = ntohl (mp->learn_limit);
433   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_DEFAULT_LEARN_LIMIT_REPLY);
434 }
435
436 static void
437 vl_api_bridge_domain_set_learn_limit_t_handler (
438   vl_api_bridge_domain_set_learn_limit_t *mp)
439 {
440   vlib_main_t *vm = vlib_get_main ();
441   bd_main_t *bdm = &bd_main;
442   vl_api_bridge_domain_set_learn_limit_reply_t *rmp;
443   int rv = 0;
444   u32 bd_id = ntohl (mp->bd_id);
445   uword *p;
446
447   if (bd_id == 0)
448     {
449       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
450       goto out;
451     }
452
453   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
454   if (p == 0)
455     {
456       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
457       goto out;
458     }
459   bd_set_learn_limit (vm, *p, ntohl (mp->learn_limit));
460 out:
461   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_LEARN_LIMIT_REPLY);
462 }
463
464 static void
465 vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t
466                                             * mp)
467 {
468   vlib_main_t *vm = vlib_get_main ();
469   bd_main_t *bdm = &bd_main;
470   vl_api_bridge_domain_set_mac_age_reply_t *rmp;
471   int rv = 0;
472   u32 bd_id = ntohl (mp->bd_id);
473   uword *p;
474
475   if (bd_id == 0)
476     {
477       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
478       goto out;
479     }
480
481   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
482   if (p == 0)
483     {
484       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
485       goto out;
486     }
487   bd_set_mac_age (vm, *p, mp->mac_age);
488 out:
489   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_MAC_AGE_REPLY);
490 }
491
492 static void
493 vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp)
494 {
495   l2_bridge_domain_add_del_args_t a = {
496     .is_add = mp->is_add,
497     .flood = mp->flood,
498     .uu_flood = mp->uu_flood,
499     .forward = mp->forward,
500     .learn = mp->learn,
501     .arp_term = mp->arp_term,
502     .arp_ufwd = mp->arp_ufwd,
503     .mac_age = mp->mac_age,
504     .bd_id = ntohl (mp->bd_id),
505     .bd_tag = mp->bd_tag
506   };
507
508   int rv = bd_add_del (&a);
509
510   vl_api_bridge_domain_add_del_reply_t *rmp;
511   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY);
512 }
513
514 static void
515 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   u32 bd_id = ntohl (mp->bd_id);
520   int rv = 0;
521
522   if ((~0 == bd_id) && (mp->is_add))
523     bd_id = bd_get_unused_id ();
524
525   if ((~0 == bd_id) && (mp->is_add))
526     rv = VNET_API_ERROR_EAGAIN;
527   else
528     {
529       l2_bridge_domain_add_del_args_t a = { .is_add = mp->is_add,
530                                             .flood = mp->flood,
531                                             .uu_flood = mp->uu_flood,
532                                             .forward = mp->forward,
533                                             .learn = mp->learn,
534                                             .arp_term = mp->arp_term,
535                                             .arp_ufwd = mp->arp_ufwd,
536                                             .mac_age = mp->mac_age,
537                                             .bd_id = bd_id,
538                                             .bd_tag = mp->bd_tag };
539       rv = bd_add_del (&a);
540     }
541   REPLY_MACRO2 (VL_API_BRIDGE_DOMAIN_ADD_DEL_V2_REPLY,
542                 ({ rmp->bd_id = htonl (bd_id); }));
543 }
544
545 static void
546 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   mp = vl_msg_api_alloc (sizeof (*mp) +
557                          (n_sw_ifs * sizeof (vl_api_bridge_domain_sw_if_t)));
558   clib_memset (mp, 0, sizeof (*mp));
559   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BRIDGE_DOMAIN_DETAILS);
560   mp->bd_id = ntohl (bd_config->bd_id);
561   mp->flood = bd_feature_flood (bd_config);
562   mp->uu_flood = bd_feature_uu_flood (bd_config);
563   mp->forward = bd_feature_forward (bd_config);
564   mp->learn = bd_feature_learn (bd_config);
565   mp->arp_term = bd_feature_arp_term (bd_config);
566   mp->arp_ufwd = bd_feature_arp_ufwd (bd_config);
567   mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index);
568   mp->uu_fwd_sw_if_index = ntohl (bd_config->uu_fwd_sw_if_index);
569   mp->mac_age = bd_config->mac_age;
570   if (bd_config->bd_tag)
571     {
572       strncpy ((char *) mp->bd_tag, (char *) bd_config->bd_tag,
573                ARRAY_LEN (mp->bd_tag) - 1);
574       mp->bd_tag[ARRAY_LEN (mp->bd_tag) - 1] = 0;
575     }
576
577   mp->context = context;
578
579   sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details;
580   vec_foreach (m, bd_config->members)
581   {
582     sw_ifs->sw_if_index = ntohl (m->sw_if_index);
583     input_cfg = vec_elt_at_index (l2im->configs, m->sw_if_index);
584     sw_ifs->shg = input_cfg->shg;
585     sw_ifs++;
586     mp->n_sw_ifs++;
587   }
588   mp->n_sw_ifs = htonl (mp->n_sw_ifs);
589
590   vl_api_send_msg (reg, (u8 *) mp);
591 }
592
593 static void
594 vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp)
595 {
596   bd_main_t *bdm = &bd_main;
597   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   reg = vl_api_client_index_to_registration (mp->client_index);
602   if (!reg)
603     return;
604
605   filter_sw_if_index = ntohl (mp->sw_if_index);
606   if (filter_sw_if_index != ~0)
607     return;                     /* UNIMPLEMENTED */
608
609   bd_id = ntohl (mp->bd_id);
610   if (bd_id == 0)
611     return;
612
613   if (bd_id == ~0)
614     bd_index = 0, end = vec_len (l2im->bd_configs);
615   else
616     {
617       bd_index = bd_find_index (bdm, bd_id);
618       if (bd_index == ~0)
619         return;
620
621       end = bd_index + 1;
622     }
623
624   for (; bd_index < end; bd_index++)
625     {
626       l2_bridge_domain_t *bd_config =
627         l2input_bd_config_from_index (l2im, bd_index);
628       /* skip placeholder bd_id 0 */
629       if (bd_config && (bd_config->bd_id > 0))
630         send_bridge_domain_details (l2im, reg, bd_config,
631                                     vec_len (bd_config->members),
632                                     mp->context);
633     }
634 }
635
636 static bd_flags_t
637 bd_flags_decode (vl_api_bd_flags_t v)
638 {
639   bd_flags_t f = L2_NONE;
640
641   v = ntohl (v);
642
643   if (v & BRIDGE_API_FLAG_LEARN)
644     f |= L2_LEARN;
645   if (v & BRIDGE_API_FLAG_FWD)
646     f |= L2_FWD;
647   if (v & BRIDGE_API_FLAG_FLOOD)
648     f |= L2_FLOOD;
649   if (v & BRIDGE_API_FLAG_UU_FLOOD)
650     f |= L2_UU_FLOOD;
651   if (v & BRIDGE_API_FLAG_ARP_TERM)
652     f |= L2_ARP_TERM;
653   if (v & BRIDGE_API_FLAG_ARP_UFWD)
654     f |= L2_ARP_UFWD;
655
656   return (f);
657 }
658
659 static void
660 vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp)
661 {
662   vlib_main_t *vm = vlib_get_main ();
663   bd_main_t *bdm = &bd_main;
664   vl_api_bridge_flags_reply_t *rmp;
665   u32 bitmap = 0;
666   int rv = 0;
667
668   bd_flags_t flags = bd_flags_decode (mp->flags);
669   u32 bd_id = ntohl (mp->bd_id);
670   if (bd_id == 0)
671     {
672       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
673       goto out;
674     }
675
676   u32 bd_index = bd_find_index (bdm, bd_id);
677   if (bd_index == ~0)
678     {
679       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
680       goto out;
681     }
682
683   bitmap = bd_set_flags (vm, bd_index, flags, mp->is_set);
684
685 out:
686   /* *INDENT-OFF* */
687   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   vl_api_l2_interface_vlan_tag_rewrite_t_handler
696   (vl_api_l2_interface_vlan_tag_rewrite_t * mp)
697 {
698   int rv = 0;
699   vl_api_l2_interface_vlan_tag_rewrite_reply_t *rmp;
700   vnet_main_t *vnm = vnet_get_main ();
701   vlib_main_t *vm = vlib_get_main ();
702   u32 vtr_op;
703
704   VALIDATE_SW_IF_INDEX (mp);
705
706   vtr_op = ntohl (mp->vtr_op);
707
708   /* The L2 code is unsuspicious */
709   switch (vtr_op)
710     {
711     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       break;
721
722     default:
723       rv = VNET_API_ERROR_INVALID_VALUE;
724       goto bad_sw_if_index;
725     }
726
727   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   BAD_SW_IF_INDEX_LABEL;
732
733   REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY);
734 }
735
736 static void
737   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   vnet_main_t *vnm = vnet_get_main ();
742   vlib_main_t *vm = vlib_get_main ();
743   u32 vtr_op;
744   int rv = 0;
745   mac_address_t b_dmac, b_smac;
746
747   VALIDATE_SW_IF_INDEX (mp);
748
749   vtr_op = ntohl (mp->vtr_op);
750
751   switch (vtr_op)
752     {
753     case L2_VTR_DISABLED:
754     case L2_VTR_PUSH_2:
755     case L2_VTR_POP_2:
756     case L2_VTR_TRANSLATE_2_1:
757       break;
758
759     default:
760       rv = VNET_API_ERROR_INVALID_VALUE;
761       goto bad_sw_if_index;
762     }
763
764   mac_address_decode (mp->b_dmac, &b_dmac);
765   mac_address_decode (mp->b_smac, &b_smac);
766
767   rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
768                         b_dmac.bytes, b_smac.bytes, ntohs (mp->b_vlanid),
769                         ntohl (mp->i_sid), ntohs (mp->outer_tag));
770
771   BAD_SW_IF_INDEX_LABEL;
772
773   REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY);
774 }
775
776 static void
777   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   int rv = 0;
782   u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
783   u32 tx_sw_if_index = ntohl (mp->tx_sw_if_index);
784   vlib_main_t *vm = vlib_get_main ();
785   vnet_main_t *vnm = vnet_get_main ();
786
787   VALIDATE_RX_SW_IF_INDEX (mp);
788
789   if (mp->enable)
790     {
791       VALIDATE_TX_SW_IF_INDEX (mp);
792       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       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   switch (rv)
803     {
804     case MODE_ERROR_ETH:
805       rv = VNET_API_ERROR_NON_ETHERNET;
806       break;
807     case MODE_ERROR_BVI_DEF:
808       rv = VNET_API_ERROR_BD_ALREADY_HAS_BVI;
809       break;
810     }
811
812   BAD_RX_SW_IF_INDEX_LABEL;
813   BAD_TX_SW_IF_INDEX_LABEL;
814
815   REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_XCONNECT_REPLY);
816 }
817
818 static int
819 l2_bd_port_type_decode (vl_api_l2_port_type_t v, l2_bd_port_type_t * l)
820 {
821   v = clib_net_to_host_u32 (v);
822
823   switch (v)
824     {
825     case L2_API_PORT_TYPE_NORMAL:
826       *l = L2_BD_PORT_TYPE_NORMAL;
827       return 0;
828     case L2_API_PORT_TYPE_BVI:
829       *l = L2_BD_PORT_TYPE_BVI;
830       return 0;
831     case L2_API_PORT_TYPE_UU_FWD:
832       *l = L2_BD_PORT_TYPE_UU_FWD;
833       return 0;
834     }
835
836   return (VNET_API_ERROR_INVALID_VALUE);
837 }
838
839 static void
840   vl_api_sw_interface_set_l2_bridge_t_handler
841   (vl_api_sw_interface_set_l2_bridge_t * mp)
842 {
843   bd_main_t *bdm = &bd_main;
844   vl_api_sw_interface_set_l2_bridge_reply_t *rmp;
845   int rv = 0;
846   vlib_main_t *vm = vlib_get_main ();
847   vnet_main_t *vnm = vnet_get_main ();
848   l2_bd_port_type_t pt;
849
850   VALIDATE_RX_SW_IF_INDEX (mp);
851   u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
852   rv = l2_bd_port_type_decode (mp->port_type, &pt);
853
854   if (0 != rv)
855     goto out;
856   if (mp->enable)
857     {
858       VALIDATE_BD_ID (mp);
859       u32 bd_id = ntohl (mp->bd_id);
860       u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id);
861
862       rv = set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE,
863                             rx_sw_if_index, bd_index, pt, mp->shg, 0);
864     }
865   else
866     {
867       rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0, pt, 0, 0);
868     }
869
870   switch (rv)
871     {
872     case MODE_ERROR_ETH:
873       rv = VNET_API_ERROR_NON_ETHERNET;
874       break;
875     case MODE_ERROR_BVI_DEF:
876       rv = VNET_API_ERROR_BD_ALREADY_HAS_BVI;
877       break;
878     }
879
880   BAD_RX_SW_IF_INDEX_LABEL;
881   BAD_BD_ID_LABEL;
882 out:
883   REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY);
884 }
885
886 static void
887 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   mp = vl_msg_api_alloc (sizeof (*mp));
897   clib_memset (mp, 0, sizeof (*mp));
898   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BD_IP_MAC_DETAILS);
899
900   mp->context = context;
901   mp->entry.bd_id = ntohl (bd_id);
902
903   ip_address_encode (ip, itype, &mp->entry.ip);
904   mac_address_encode (mac, mp->entry.mac);
905
906   vl_api_send_msg (reg, (u8 *) mp);
907 }
908
909 static void
910 vl_api_bd_ip_mac_dump_t_handler (vl_api_bd_ip_mac_dump_t * mp)
911 {
912   vpe_api_main_t *am = &vpe_api_main;
913   bd_main_t *bdm = &bd_main;
914   l2_bridge_domain_t *bd_config;
915   u32 bd_id = ntohl (mp->bd_id);
916   u32 bd_index, start, end;
917   vl_api_registration_t *reg;
918   uword *p;
919
920   reg = vl_api_client_index_to_registration (mp->client_index);
921   if (!reg)
922     return;
923
924   /* see bd_id: ~0 means "any" */
925   if (bd_id == ~0)
926     {
927       start = 1;
928       end = vec_len (l2input_main.bd_configs);
929     }
930   else
931     {
932       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
933       if (p == 0)
934         return;
935
936       bd_index = p[0];
937       vec_validate (l2input_main.bd_configs, bd_index);
938       start = bd_index;
939       end = start + 1;
940     }
941
942   for (bd_index = start; bd_index < end; bd_index++)
943     {
944       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
945       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           bd_id = bd_config->bd_id;
952
953          /* *INDENT-OFF* */
954          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          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 vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp)
982 {
983   ip46_address_t ip_addr = ip46_address_initializer;
984   vl_api_bd_ip_mac_add_del_reply_t *rmp;
985   bd_main_t *bdm = &bd_main;
986   u32 bd_index, bd_id;
987   mac_address_t mac;
988   ip46_type_t type;
989   int rv = 0;
990   uword *p;
991
992   bd_id = ntohl (mp->entry.bd_id);
993
994   if (bd_id == 0)
995     {
996       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
997       goto out;
998     }
999
1000   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1001   if (p == 0)
1002     {
1003       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1004       goto out;
1005     }
1006   bd_index = p[0];
1007
1008   type = ip_address_decode (&mp->entry.ip, &ip_addr);
1009   mac_address_decode (mp->entry.mac, &mac);
1010
1011   if (bd_add_del_ip_mac (bd_index, type, &ip_addr, &mac, mp->is_add))
1012     rv = VNET_API_ERROR_UNSPECIFIED;
1013
1014 out:
1015   REPLY_MACRO (VL_API_BD_IP_MAC_ADD_DEL_REPLY);
1016 }
1017
1018 static void
1019 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   bd_main_t *bdm = &bd_main;
1023   u32 bd_index, bd_id;
1024   int rv = 0;
1025   uword *p;
1026
1027   bd_id = ntohl (mp->bd_id);
1028
1029   if (bd_id == 0)
1030     {
1031       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
1032       goto out;
1033     }
1034
1035   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1036   if (p == 0)
1037     {
1038       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1039       goto out;
1040     }
1041   bd_index = p[0];
1042
1043   bd_flush_ip_mac (bd_index);
1044
1045 out:
1046   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 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   vnet_main_t *vnm = vnet_get_main ();
1059
1060   VALIDATE_SW_IF_INDEX (mp);
1061
1062   // enable/disable the feature
1063   l2_efp_filter_configure (vnm, ntohl (mp->sw_if_index), mp->enable_disable);
1064   rv = vnm->api_errno;
1065
1066   BAD_SW_IF_INDEX_LABEL;
1067   REPLY_MACRO (VL_API_L2_INTERFACE_EFP_FILTER_REPLY);
1068 }
1069
1070 static void
1071 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   int rv = 0;
1079
1080   VALIDATE_RX_SW_IF_INDEX (mp);
1081   VALIDATE_TX_SW_IF_INDEX (mp);
1082
1083   rv = vnet_l2_patch_add_del (ntohl (mp->rx_sw_if_index),
1084                               ntohl (mp->tx_sw_if_index),
1085                               (int) (mp->is_add != 0));
1086
1087   BAD_RX_SW_IF_INDEX_LABEL;
1088   BAD_TX_SW_IF_INDEX_LABEL;
1089
1090   REPLY_MACRO (VL_API_L2_PATCH_ADD_DEL_REPLY);
1091 }
1092
1093 static void
1094 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   int rv = 0;
1098   u32 sw_if_index = ntohl (mp->sw_if_index);
1099
1100   VALIDATE_SW_IF_INDEX (mp);
1101
1102   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VPATH, mp->enable);
1103   vnet_feature_enable_disable ("ip4-unicast", "vpath-input-ip4",
1104                                sw_if_index, mp->enable, 0, 0);
1105   vnet_feature_enable_disable ("ip4-multicast", "vpath-input-ip4",
1106                                sw_if_index, mp->enable, 0, 0);
1107   vnet_feature_enable_disable ("ip6-unicast", "vpath-input-ip6",
1108                                sw_if_index, mp->enable, 0, 0);
1109   vnet_feature_enable_disable ("ip6-multicast", "vpath-input-ip6",
1110                                sw_if_index, mp->enable, 0, 0);
1111
1112   BAD_SW_IF_INDEX_LABEL;
1113
1114   REPLY_MACRO (VL_API_SW_INTERFACE_SET_VPATH_REPLY);
1115 }
1116
1117 static void
1118 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   mac_address_decode (mp->mac, &mac);
1126
1127   rv = l2_bvi_create (ntohl (mp->user_instance), &mac, &sw_if_index);
1128
1129   /* *INDENT-OFF* */
1130   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 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   rv = l2_bvi_delete (ntohl (mp->sw_if_index));
1144
1145   REPLY_MACRO (VL_API_BVI_DELETE_REPLY);
1146 }
1147
1148 static bool
1149 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   if (e1 == NULL || e2 == NULL)
1153     return false;
1154   return (ip46_address_is_equal (&e1->ip, &e2->ip) &&
1155           (e1->sw_if_index == e2->sw_if_index) &&
1156           (mac_address_equal (&e1->mac, &e2->mac)));
1157 }
1158
1159 static uword
1160 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   volatile f64 last = vlib_time_now (vm);
1167   volatile l2_arp_term_publish_event_t last_event = { };
1168
1169   l2_arp_term_main_t *l2am = &l2_arp_term_main;
1170
1171   while (1)
1172     {
1173       uword event_type = L2_ARP_TERM_EVENT_PUBLISH;
1174       vpe_client_registration_t *reg;
1175       f64 now;
1176
1177       vlib_process_wait_for_event (vm);
1178
1179       vlib_process_get_event_data (vm, &event_type);
1180       now = vlib_time_now (vm);
1181
1182       if (event_type == L2_ARP_TERM_EVENT_PUBLISH)
1183         {
1184           l2_arp_term_publish_event_t *event;
1185
1186           vec_foreach (event, l2am->publish_events)
1187           {
1188             /* dampen duplicate events - cast away volatile */
1189             if (l2_arp_term_publish_event_is_equal
1190                 (event, (l2_arp_term_publish_event_t *) & last_event) &&
1191                 (now - last) < 10.0)
1192               {
1193                 continue;
1194               }
1195             last_event = *event;
1196             last = now;
1197
1198             pool_foreach (reg, vpe_api_main.l2_arp_term_events_registrations)
1199               {
1200                 vl_api_registration_t *vl_reg;
1201                 vl_reg =
1202                   vl_api_client_index_to_registration (reg->client_index);
1203                 ALWAYS_ASSERT (vl_reg != NULL);
1204
1205                 if (vl_reg && vl_api_can_send_msg (vl_reg))
1206                   {
1207                     vl_api_l2_arp_term_event_t *vevent;
1208                     vevent = vl_msg_api_alloc (sizeof *vevent);
1209                     clib_memset (vevent, 0, sizeof *vevent);
1210                     vevent->_vl_msg_id =
1211                       htons (REPLY_MSG_ID_BASE + VL_API_L2_ARP_TERM_EVENT);
1212                     vevent->client_index = reg->client_index;
1213                     vevent->pid = reg->client_pid;
1214                     ip_address_encode (&event->ip, event->type, &vevent->ip);
1215                     vevent->sw_if_index = htonl (event->sw_if_index);
1216                     mac_address_encode (&event->mac, vevent->mac);
1217                     vl_api_send_msg (vl_reg, (u8 *) vevent);
1218                   }
1219               }
1220           }
1221           vec_reset_length (l2am->publish_events);
1222         }
1223     }
1224
1225   return 0;
1226 }
1227
1228 /* *INDENT-OFF* */
1229 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 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   vpe_api_main_t *am = &vpe_api_main;
1242   vpe_client_registration_t *rp;
1243   int rv = 0;
1244   uword *p;
1245
1246   p = hash_get (am->l2_arp_term_events_registration_hash, mp->client_index);
1247
1248   if (p)
1249     {
1250       if (mp->enable)
1251         {
1252           clib_warning ("pid %d: already enabled...", mp->pid);
1253           rv = VNET_API_ERROR_INVALID_REGISTRATION;
1254           goto reply;
1255         }
1256       else
1257         {
1258           rp = pool_elt_at_index (am->l2_arp_term_events_registrations, p[0]);
1259           pool_put (am->l2_arp_term_events_registrations, rp);
1260           hash_unset (am->l2_arp_term_events_registration_hash,
1261                       mp->client_index);
1262           if (pool_elts (am->l2_arp_term_events_registrations) == 0)
1263             l2_arp_term_set_publisher_node (false);
1264           goto reply;
1265         }
1266     }
1267   if (mp->enable == 0)
1268     {
1269       clib_warning ("pid %d: already disabled...", mp->pid);
1270       rv = VNET_API_ERROR_INVALID_REGISTRATION;
1271       goto reply;
1272     }
1273   pool_get (am->l2_arp_term_events_registrations, rp);
1274   rp->client_index = mp->client_index;
1275   rp->client_pid = mp->pid;
1276   hash_set (am->l2_arp_term_events_registration_hash, rp->client_index,
1277             rp - am->l2_arp_term_events_registrations);
1278   l2_arp_term_set_publisher_node (true);
1279
1280 reply:
1281   REPLY_MACRO (VL_API_WANT_L2_ARP_TERM_EVENTS_REPLY);
1282 }
1283
1284 static clib_error_t *
1285 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   am = &vpe_api_main;
1292
1293   /* remove from the registration hash */
1294   p = hash_get (am->l2_arp_term_events_registration_hash, client_index);
1295
1296   if (p)
1297     {
1298       rp = pool_elt_at_index (am->l2_arp_term_events_registrations, p[0]);
1299       pool_put (am->l2_arp_term_events_registrations, rp);
1300       hash_unset (am->l2_arp_term_events_registration_hash, client_index);
1301       if (pool_elts (am->l2_arp_term_events_registrations) == 0)
1302         l2_arp_term_set_publisher_node (false);
1303     }
1304   return (NULL);
1305 }
1306
1307 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 l2_api_hookup (vlib_main_t * vm)
1312 {
1313   api_main_t *am = vlibapi_get_main ();
1314
1315   /* Mark VL_API_BRIDGE_DOMAIN_DUMP as mp safe */
1316   vl_api_set_msg_thread_safe (am, VL_API_BRIDGE_DOMAIN_DUMP, 1);
1317
1318   /*
1319    * Set up the (msg_name, crc, message-id) table
1320    */
1321   REPLY_MSG_ID_BASE = setup_message_id_table ();
1322
1323   return 0;
1324 }
1325
1326 VLIB_API_INIT_FUNCTION (l2_api_hookup);
1327
1328 /*
1329  * fd.io coding-style-patch-verification: ON
1330  *
1331  * Local Variables:
1332  * eval: (c-set-style "gnu")
1333  * End:
1334  */