L2 BD: introduce a BD interface on which to send UU packets
[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  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25 #include <vnet/l2/l2_input.h>
26 #include <vnet/l2/l2_fib.h>
27 #include <vnet/l2/l2_vtr.h>
28 #include <vnet/l2/l2_learn.h>
29 #include <vnet/l2/l2_bd.h>
30
31 #include <vnet/vnet_msg_enum.h>
32
33 #define vl_typedefs             /* define message structures */
34 #include <vnet/vnet_all_api_h.h>
35 #undef vl_typedefs
36
37 #define vl_endianfun            /* define message structures */
38 #include <vnet/vnet_all_api_h.h>
39 #undef vl_endianfun
40
41 #define vl_api_bridge_domain_details_t_endian vl_noop_handler
42 #define vl_api_bridge_domain_details_t_print vl_noop_handler
43
44 /* instantiate all the print functions we know about */
45 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
46 #define vl_printfun
47 #include <vnet/vnet_all_api_h.h>
48 #undef vl_printfun
49
50 #include <vlibapi/api_helper_macros.h>
51
52 #define foreach_vpe_api_msg                                 \
53 _(L2_XCONNECT_DUMP, l2_xconnect_dump)                       \
54 _(L2_FIB_CLEAR_TABLE, l2_fib_clear_table)                   \
55 _(L2_FIB_TABLE_DUMP, l2_fib_table_dump)                     \
56 _(L2FIB_FLUSH_ALL, l2fib_flush_all)                         \
57 _(L2FIB_FLUSH_INT, l2fib_flush_int)                         \
58 _(L2FIB_FLUSH_BD, l2fib_flush_bd)                           \
59 _(L2FIB_ADD_DEL, l2fib_add_del)                             \
60 _(WANT_L2_MACS_EVENTS, want_l2_macs_events)                 \
61 _(L2_FLAGS, l2_flags)                                       \
62 _(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect)   \
63 _(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge)       \
64 _(L2_PATCH_ADD_DEL, l2_patch_add_del)                           \
65 _(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter)             \
66 _(BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del)                         \
67 _(BD_IP_MAC_DUMP, bd_ip_mac_dump)                               \
68 _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del)                 \
69 _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump)                       \
70 _(BRIDGE_FLAGS, bridge_flags)                                   \
71 _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \
72 _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite)   \
73 _(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age)         \
74 _(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath)
75
76 static void
77 send_l2_xconnect_details (vl_api_registration_t * reg, u32 context,
78                           u32 rx_sw_if_index, u32 tx_sw_if_index)
79 {
80   vl_api_l2_xconnect_details_t *mp;
81
82   mp = vl_msg_api_alloc (sizeof (*mp));
83   memset (mp, 0, sizeof (*mp));
84   mp->_vl_msg_id = ntohs (VL_API_L2_XCONNECT_DETAILS);
85   mp->context = context;
86   mp->rx_sw_if_index = htonl (rx_sw_if_index);
87   mp->tx_sw_if_index = htonl (tx_sw_if_index);
88
89   vl_api_send_msg (reg, (u8 *) mp);
90 }
91
92 static void
93 vl_api_l2_xconnect_dump_t_handler (vl_api_l2_xconnect_dump_t * mp)
94 {
95   vl_api_registration_t *reg;
96   vnet_main_t *vnm = vnet_get_main ();
97   vnet_interface_main_t *im = &vnm->interface_main;
98   l2input_main_t *l2im = &l2input_main;
99   vnet_sw_interface_t *swif;
100   l2_input_config_t *config;
101
102   reg = vl_api_client_index_to_registration (mp->client_index);
103   if (!reg)
104     return;
105
106   /* *INDENT-OFF* */
107   pool_foreach (swif, im->sw_interfaces,
108   ({
109     config = vec_elt_at_index (l2im->configs, swif->sw_if_index);
110     if (config->xconnect)
111       send_l2_xconnect_details (reg, mp->context, swif->sw_if_index,
112                                 config->output_sw_if_index);
113   }));
114   /* *INDENT-ON* */
115 }
116
117 static void
118 vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp)
119 {
120   int rv = 0;
121   vl_api_l2_fib_clear_table_reply_t *rmp;
122
123   /* Clear all MACs including static MACs  */
124   l2fib_clear_table ();
125
126   REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY);
127 }
128
129 static void
130 send_l2fib_table_entry (vpe_api_main_t * am,
131                         vl_api_registration_t * reg,
132                         l2fib_entry_key_t * l2fe_key,
133                         l2fib_entry_result_t * l2fe_res, u32 context)
134 {
135   vl_api_l2_fib_table_details_t *mp;
136
137   mp = vl_msg_api_alloc (sizeof (*mp));
138   memset (mp, 0, sizeof (*mp));
139   mp->_vl_msg_id = ntohs (VL_API_L2_FIB_TABLE_DETAILS);
140
141   mp->bd_id =
142     ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id);
143
144   clib_memcpy (mp->mac, l2fe_key->fields.mac, 6);
145   mp->sw_if_index = ntohl (l2fe_res->fields.sw_if_index);
146   mp->static_mac = (l2fib_entry_result_is_set_STATIC (l2fe_res) ? 1 : 0);
147   mp->filter_mac = (l2fib_entry_result_is_set_FILTER (l2fe_res) ? 1 : 0);
148   mp->bvi_mac = (l2fib_entry_result_is_set_BVI (l2fe_res) ? 1 : 0);
149   mp->context = context;
150
151   vl_api_send_msg (reg, (u8 *) mp);
152 }
153
154 static void
155 vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp)
156 {
157   vpe_api_main_t *am = &vpe_api_main;
158   bd_main_t *bdm = &bd_main;
159   l2fib_entry_key_t *l2fe_key = NULL;
160   l2fib_entry_result_t *l2fe_res = NULL;
161   u32 ni, bd_id = ntohl (mp->bd_id);
162   u32 bd_index;
163   vl_api_registration_t *reg;
164   uword *p;
165
166   reg = vl_api_client_index_to_registration (mp->client_index);
167   if (!reg)
168     return;
169
170   /* see l2fib_table_dump: ~0 means "any" */
171   if (bd_id == ~0)
172     bd_index = ~0;
173   else
174     {
175       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
176       if (p == 0)
177         return;
178
179       bd_index = p[0];
180     }
181
182   l2fib_table_dump (bd_index, &l2fe_key, &l2fe_res);
183
184   vec_foreach_index (ni, l2fe_key)
185   {
186     send_l2fib_table_entry (am, reg, vec_elt_at_index (l2fe_key, ni),
187                             vec_elt_at_index (l2fe_res, ni), mp->context);
188   }
189   vec_free (l2fe_key);
190   vec_free (l2fe_res);
191 }
192
193 static void
194 vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp)
195 {
196   bd_main_t *bdm = &bd_main;
197   l2input_main_t *l2im = &l2input_main;
198   vl_api_l2fib_add_del_reply_t *rmp;
199   int rv = 0;
200   u32 bd_id = ntohl (mp->bd_id);
201   uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
202
203   if (!p)
204     {
205       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
206       goto bad_sw_if_index;
207     }
208   u32 bd_index = p[0];
209
210   u8 mac[6];
211
212   clib_memcpy (mac, mp->mac, 6);
213   if (mp->is_add)
214     {
215       if (mp->filter_mac)
216         l2fib_add_filter_entry (mac, bd_index);
217       else
218         {
219           l2fib_entry_result_flags_t flags = L2FIB_ENTRY_RESULT_FLAG_NONE;
220           u32 sw_if_index = ntohl (mp->sw_if_index);
221           VALIDATE_SW_IF_INDEX (mp);
222           if (vec_len (l2im->configs) <= sw_if_index)
223             {
224               rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
225               goto bad_sw_if_index;
226             }
227           else
228             {
229               l2_input_config_t *config;
230               config = vec_elt_at_index (l2im->configs, sw_if_index);
231               if (config->bridge == 0)
232                 {
233                   rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
234                   goto bad_sw_if_index;
235                 }
236             }
237           if (mp->static_mac)
238             flags |= L2FIB_ENTRY_RESULT_FLAG_STATIC;
239           if (mp->bvi_mac)
240             flags |= L2FIB_ENTRY_RESULT_FLAG_BVI;
241           l2fib_add_entry (mac, bd_index, sw_if_index, flags);
242         }
243     }
244   else
245     {
246       u32 sw_if_index = ntohl (mp->sw_if_index);
247       if (l2fib_del_entry (mac, bd_index, sw_if_index))
248         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
249     }
250
251   BAD_SW_IF_INDEX_LABEL;
252
253   REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY);
254 }
255
256 static void
257 vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t * mp)
258 {
259   int rv = 0;
260   vl_api_want_l2_macs_events_reply_t *rmp;
261   l2learn_main_t *lm = &l2learn_main;
262   l2fib_main_t *fm = &l2fib_main;
263   u32 pid = ntohl (mp->pid);
264   u32 learn_limit = ntohl (mp->learn_limit);
265
266   if (mp->enable_disable)
267     {
268       if (lm->client_pid == 0)
269         {
270           lm->client_pid = pid;
271           lm->client_index = mp->client_index;
272
273           if (mp->max_macs_in_event)
274             fm->max_macs_in_event = mp->max_macs_in_event * 10;
275           else
276             fm->max_macs_in_event = L2FIB_EVENT_MAX_MACS_DEFAULT;
277
278           if (mp->scan_delay)
279             fm->event_scan_delay = (f64) (mp->scan_delay) * 10e-3;
280           else
281             fm->event_scan_delay = L2FIB_EVENT_SCAN_DELAY_DEFAULT;
282
283           /* change learn limit and flush all learned MACs */
284           if (learn_limit && (learn_limit < L2LEARN_DEFAULT_LIMIT))
285             lm->global_learn_limit = learn_limit;
286           else
287             lm->global_learn_limit = L2FIB_EVENT_LEARN_LIMIT_DEFAULT;
288
289           l2fib_flush_all_mac (vlib_get_main ());
290         }
291       else if (lm->client_pid != pid)
292         {
293           rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT;
294           goto exit;
295         }
296     }
297   else if (lm->client_pid)
298     {
299       lm->client_pid = 0;
300       lm->client_index = 0;
301       if (learn_limit && (learn_limit < L2LEARN_DEFAULT_LIMIT))
302         lm->global_learn_limit = learn_limit;
303       else
304         lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT;
305     }
306
307 exit:
308   REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS_REPLY);
309 }
310
311 static void
312 vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp)
313 {
314   int rv = 0;
315   vlib_main_t *vm = vlib_get_main ();
316   vl_api_l2fib_flush_int_reply_t *rmp;
317
318   VALIDATE_SW_IF_INDEX (mp);
319
320   u32 sw_if_index = ntohl (mp->sw_if_index);
321   l2fib_flush_int_mac (vm, sw_if_index);
322
323   BAD_SW_IF_INDEX_LABEL;
324   REPLY_MACRO (VL_API_L2FIB_FLUSH_INT_REPLY);
325 }
326
327 static void
328 vl_api_l2fib_flush_all_t_handler (vl_api_l2fib_flush_all_t * mp)
329 {
330   int rv = 0;
331   vl_api_l2fib_flush_all_reply_t *rmp;
332
333   l2fib_flush_all_mac (vlib_get_main ());
334   REPLY_MACRO (VL_API_L2FIB_FLUSH_ALL_REPLY);
335 }
336
337 static void
338 vl_api_l2fib_flush_bd_t_handler (vl_api_l2fib_flush_bd_t * mp)
339 {
340   int rv = 0;
341   vlib_main_t *vm = vlib_get_main ();
342   bd_main_t *bdm = &bd_main;
343   vl_api_l2fib_flush_bd_reply_t *rmp;
344
345   u32 bd_id = ntohl (mp->bd_id);
346   uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
347   if (p == 0)
348     {
349       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
350       goto out;
351     }
352   l2fib_flush_bd_mac (vm, *p);
353 out:
354   REPLY_MACRO (VL_API_L2FIB_FLUSH_BD_REPLY);
355 }
356
357 static void
358 vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp)
359 {
360   vl_api_l2_flags_reply_t *rmp;
361   int rv = 0;
362   u32 rbm = 0;
363
364   VALIDATE_SW_IF_INDEX (mp);
365
366   u32 sw_if_index = ntohl (mp->sw_if_index);
367   u32 flags = ntohl (mp->feature_bitmap);
368   u32 bitmap = 0;
369
370   if (flags & L2_LEARN)
371     bitmap |= L2INPUT_FEAT_LEARN;
372
373   if (flags & L2_FWD)
374     bitmap |= L2INPUT_FEAT_FWD;
375
376   if (flags & L2_FLOOD)
377     bitmap |= L2INPUT_FEAT_FLOOD;
378
379   if (flags & L2_UU_FLOOD)
380     bitmap |= L2INPUT_FEAT_UU_FLOOD;
381
382   if (flags & L2_ARP_TERM)
383     bitmap |= L2INPUT_FEAT_ARP_TERM;
384
385   rbm = l2input_intf_bitmap_enable (sw_if_index, bitmap, mp->is_set);
386
387   BAD_SW_IF_INDEX_LABEL;
388
389   /* *INDENT-OFF* */
390   REPLY_MACRO2(VL_API_L2_FLAGS_REPLY,
391   ({
392     rmp->resulting_feature_bitmap = ntohl(rbm);
393   }));
394   /* *INDENT-ON* */
395 }
396
397 static void
398 vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t
399                                             * mp)
400 {
401   vlib_main_t *vm = vlib_get_main ();
402   bd_main_t *bdm = &bd_main;
403   vl_api_bridge_domain_set_mac_age_reply_t *rmp;
404   int rv = 0;
405   u32 bd_id = ntohl (mp->bd_id);
406   uword *p;
407
408   if (bd_id == 0)
409     {
410       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
411       goto out;
412     }
413
414   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
415   if (p == 0)
416     {
417       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
418       goto out;
419     }
420   bd_set_mac_age (vm, *p, mp->mac_age);
421 out:
422   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_MAC_AGE_REPLY);
423 }
424
425 static void
426 vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp)
427 {
428   l2_bridge_domain_add_del_args_t a = {
429     .is_add = mp->is_add,
430     .flood = mp->flood,
431     .uu_flood = mp->uu_flood,
432     .forward = mp->forward,
433     .learn = mp->learn,
434     .arp_term = mp->arp_term,
435     .mac_age = mp->mac_age,
436     .bd_id = ntohl (mp->bd_id),
437     .bd_tag = mp->bd_tag
438   };
439
440   int rv = bd_add_del (&a);
441
442   vl_api_bridge_domain_add_del_reply_t *rmp;
443   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY);
444 }
445
446 static void
447 send_bridge_domain_details (l2input_main_t * l2im,
448                             vl_api_registration_t * reg,
449                             l2_bridge_domain_t * bd_config,
450                             u32 n_sw_ifs, u32 context)
451 {
452   vl_api_bridge_domain_details_t *mp;
453   l2_flood_member_t *m;
454   vl_api_bridge_domain_sw_if_t *sw_ifs;
455   l2_input_config_t *input_cfg;
456
457   mp = vl_msg_api_alloc (sizeof (*mp) +
458                          (n_sw_ifs * sizeof (vl_api_bridge_domain_sw_if_t)));
459   memset (mp, 0, sizeof (*mp));
460   mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_DETAILS);
461   mp->bd_id = ntohl (bd_config->bd_id);
462   mp->flood = bd_feature_flood (bd_config);
463   mp->uu_flood = bd_feature_uu_flood (bd_config);
464   mp->forward = bd_feature_forward (bd_config);
465   mp->learn = bd_feature_learn (bd_config);
466   mp->arp_term = bd_feature_arp_term (bd_config);
467   mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index);
468   mp->uu_fwd_sw_if_index = ntohl (bd_config->uu_fwd_sw_if_index);
469   mp->mac_age = bd_config->mac_age;
470   if (bd_config->bd_tag)
471     {
472       strncpy ((char *) mp->bd_tag, (char *) bd_config->bd_tag,
473                ARRAY_LEN (mp->bd_tag) - 1);
474       mp->bd_tag[ARRAY_LEN (mp->bd_tag) - 1] = 0;
475     }
476
477   mp->context = context;
478
479   sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details;
480   vec_foreach (m, bd_config->members)
481   {
482     sw_ifs->sw_if_index = ntohl (m->sw_if_index);
483     input_cfg = vec_elt_at_index (l2im->configs, m->sw_if_index);
484     sw_ifs->shg = input_cfg->shg;
485     sw_ifs++;
486     mp->n_sw_ifs++;
487   }
488   mp->n_sw_ifs = htonl (mp->n_sw_ifs);
489
490   vl_api_send_msg (reg, (u8 *) mp);
491 }
492
493 static void
494 vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp)
495 {
496   bd_main_t *bdm = &bd_main;
497   l2input_main_t *l2im = &l2input_main;
498   vl_api_registration_t *reg;
499   u32 bd_id, bd_index, end;
500
501   reg = vl_api_client_index_to_registration (mp->client_index);
502   if (!reg)
503     return;
504
505   bd_id = ntohl (mp->bd_id);
506   if (bd_id == 0)
507     return;
508
509   if (bd_id == ~0)
510     bd_index = 0, end = vec_len (l2im->bd_configs);
511   else
512     {
513       bd_index = bd_find_index (bdm, bd_id);
514       if (bd_index == ~0)
515         return;
516
517       end = bd_index + 1;
518     }
519
520   for (; bd_index < end; bd_index++)
521     {
522       l2_bridge_domain_t *bd_config =
523         l2input_bd_config_from_index (l2im, bd_index);
524       /* skip dummy bd_id 0 */
525       if (bd_config && (bd_config->bd_id > 0))
526         send_bridge_domain_details (l2im, reg, bd_config,
527                                     vec_len (bd_config->members),
528                                     mp->context);
529     }
530 }
531
532 static bd_flags_t
533 bd_flags_decode (vl_api_bd_flags_t v)
534 {
535   bd_flags_t f = L2_NONE;
536
537   v = ntohl (v);
538
539   if (v & BRIDGE_API_FLAG_LEARN)
540     f |= L2_LEARN;
541   if (v & BRIDGE_API_FLAG_FWD)
542     f |= L2_FWD;
543   if (v & BRIDGE_API_FLAG_FLOOD)
544     f |= L2_FLOOD;
545   if (v & BRIDGE_API_FLAG_UU_FLOOD)
546     f |= L2_UU_FLOOD;
547   if (v & BRIDGE_API_FLAG_ARP_TERM)
548     f |= L2_ARP_TERM;
549
550   return (f);
551 }
552
553 static void
554 vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp)
555 {
556   vlib_main_t *vm = vlib_get_main ();
557   bd_main_t *bdm = &bd_main;
558   vl_api_bridge_flags_reply_t *rmp;
559   int rv = 0;
560
561   bd_flags_t flags = bd_flags_decode (mp->flags);
562   u32 bd_id = ntohl (mp->bd_id);
563   if (bd_id == 0)
564     {
565       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
566       goto out;
567     }
568
569   u32 bd_index = bd_find_index (bdm, bd_id);
570   if (bd_index == ~0)
571     {
572       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
573       goto out;
574     }
575
576   u32 bitmap = bd_set_flags (vm, bd_index, flags, mp->is_set);
577
578 out:
579   /* *INDENT-OFF* */
580   REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY,
581   ({
582     rmp->resulting_feature_bitmap = ntohl(bitmap);
583   }));
584   /* *INDENT-ON* */
585 }
586
587 static void
588   vl_api_l2_interface_vlan_tag_rewrite_t_handler
589   (vl_api_l2_interface_vlan_tag_rewrite_t * mp)
590 {
591   int rv = 0;
592   vl_api_l2_interface_vlan_tag_rewrite_reply_t *rmp;
593   vnet_main_t *vnm = vnet_get_main ();
594   vlib_main_t *vm = vlib_get_main ();
595   u32 vtr_op;
596
597   VALIDATE_SW_IF_INDEX (mp);
598
599   vtr_op = ntohl (mp->vtr_op);
600
601   /* The L2 code is unsuspicious */
602   switch (vtr_op)
603     {
604     case L2_VTR_DISABLED:
605     case L2_VTR_PUSH_1:
606     case L2_VTR_PUSH_2:
607     case L2_VTR_POP_1:
608     case L2_VTR_POP_2:
609     case L2_VTR_TRANSLATE_1_1:
610     case L2_VTR_TRANSLATE_1_2:
611     case L2_VTR_TRANSLATE_2_1:
612     case L2_VTR_TRANSLATE_2_2:
613       break;
614
615     default:
616       rv = VNET_API_ERROR_INVALID_VALUE;
617       goto bad_sw_if_index;
618     }
619
620   rv = l2vtr_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
621                         ntohl (mp->push_dot1q), ntohl (mp->tag1),
622                         ntohl (mp->tag2));
623
624   BAD_SW_IF_INDEX_LABEL;
625
626   REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY);
627 }
628
629 static void
630   vl_api_l2_interface_pbb_tag_rewrite_t_handler
631   (vl_api_l2_interface_pbb_tag_rewrite_t * mp)
632 {
633   vl_api_l2_interface_pbb_tag_rewrite_reply_t *rmp;
634   vnet_main_t *vnm = vnet_get_main ();
635   vlib_main_t *vm = vlib_get_main ();
636   u32 vtr_op;
637   int rv = 0;
638
639   VALIDATE_SW_IF_INDEX (mp);
640
641   vtr_op = ntohl (mp->vtr_op);
642
643   switch (vtr_op)
644     {
645     case L2_VTR_DISABLED:
646     case L2_VTR_PUSH_2:
647     case L2_VTR_POP_2:
648     case L2_VTR_TRANSLATE_2_1:
649       break;
650
651     default:
652       rv = VNET_API_ERROR_INVALID_VALUE;
653       goto bad_sw_if_index;
654     }
655
656   rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
657                         mp->b_dmac, mp->b_smac, ntohs (mp->b_vlanid),
658                         ntohl (mp->i_sid), ntohs (mp->outer_tag));
659
660   BAD_SW_IF_INDEX_LABEL;
661
662   REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY);
663 }
664
665 static void
666   vl_api_sw_interface_set_l2_xconnect_t_handler
667   (vl_api_sw_interface_set_l2_xconnect_t * mp)
668 {
669   vl_api_sw_interface_set_l2_xconnect_reply_t *rmp;
670   int rv = 0;
671   u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
672   u32 tx_sw_if_index = ntohl (mp->tx_sw_if_index);
673   vlib_main_t *vm = vlib_get_main ();
674   vnet_main_t *vnm = vnet_get_main ();
675
676   VALIDATE_RX_SW_IF_INDEX (mp);
677
678   if (mp->enable)
679     {
680       VALIDATE_TX_SW_IF_INDEX (mp);
681       rv = set_int_l2_mode (vm, vnm, MODE_L2_XC,
682                             rx_sw_if_index, 0,
683                             L2_BD_PORT_TYPE_NORMAL, 0, tx_sw_if_index);
684     }
685   else
686     {
687       rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0,
688                             L2_BD_PORT_TYPE_NORMAL, 0, 0);
689     }
690
691   BAD_RX_SW_IF_INDEX_LABEL;
692   BAD_TX_SW_IF_INDEX_LABEL;
693
694   REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_XCONNECT_REPLY);
695 }
696
697 static int
698 l2_bd_port_type_decode (vl_api_l2_port_type_t v, l2_bd_port_type_t * l)
699 {
700   v = clib_net_to_host_u32 (v);
701
702   switch (v)
703     {
704     case L2_API_PORT_TYPE_NORMAL:
705       *l = L2_BD_PORT_TYPE_NORMAL;
706       return 0;
707     case L2_API_PORT_TYPE_BVI:
708       *l = L2_BD_PORT_TYPE_BVI;
709       return 0;
710     case L2_API_PORT_TYPE_UU_FWD:
711       *l = L2_BD_PORT_TYPE_UU_FWD;
712       return 0;
713     }
714
715   return (VNET_API_ERROR_INVALID_VALUE);
716 }
717
718 static void
719   vl_api_sw_interface_set_l2_bridge_t_handler
720   (vl_api_sw_interface_set_l2_bridge_t * mp)
721 {
722   bd_main_t *bdm = &bd_main;
723   vl_api_sw_interface_set_l2_bridge_reply_t *rmp;
724   int rv = 0;
725   vlib_main_t *vm = vlib_get_main ();
726   vnet_main_t *vnm = vnet_get_main ();
727   l2_bd_port_type_t pt;
728
729   VALIDATE_RX_SW_IF_INDEX (mp);
730   u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
731   rv = l2_bd_port_type_decode (mp->port_type, &pt);
732
733   if (0 != rv)
734     goto out;
735   if (mp->enable)
736     {
737       VALIDATE_BD_ID (mp);
738       u32 bd_id = ntohl (mp->bd_id);
739       u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id);
740
741       rv = set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE,
742                             rx_sw_if_index, bd_index, pt, mp->shg, 0);
743     }
744   else
745     {
746       rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0, pt, 0, 0);
747     }
748
749   BAD_RX_SW_IF_INDEX_LABEL;
750   BAD_BD_ID_LABEL;
751 out:
752   REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY);
753 }
754
755 static void
756 send_bd_ip_mac_entry (vpe_api_main_t * am,
757                       vl_api_registration_t * reg,
758                       u32 bd_id, u8 is_ipv6,
759                       u8 * ip_address, u8 * mac_address, u32 context)
760 {
761   vl_api_bd_ip_mac_details_t *mp;
762
763   mp = vl_msg_api_alloc (sizeof (*mp));
764   memset (mp, 0, sizeof (*mp));
765   mp->_vl_msg_id = ntohs (VL_API_BD_IP_MAC_DETAILS);
766
767   mp->bd_id = ntohl (bd_id);
768
769   clib_memcpy (mp->mac_address, mac_address, 6);
770   mp->is_ipv6 = is_ipv6;
771   clib_memcpy (mp->ip_address, ip_address, (is_ipv6) ? 16 : 4);
772   mp->context = context;
773
774   vl_api_send_msg (reg, (u8 *) mp);
775 }
776
777 static void
778 vl_api_bd_ip_mac_dump_t_handler (vl_api_bd_ip_mac_dump_t * mp)
779 {
780   vpe_api_main_t *am = &vpe_api_main;
781   bd_main_t *bdm = &bd_main;
782   l2_bridge_domain_t *bd_config;
783   u32 bd_id = ntohl (mp->bd_id);
784   u32 bd_index, start, end;
785   vl_api_registration_t *reg;
786   uword *p;
787
788   reg = vl_api_client_index_to_registration (mp->client_index);
789   if (!reg)
790     return;
791
792   /* see bd_id: ~0 means "any" */
793   if (bd_id == ~0)
794     {
795       start = 1;
796       end = vec_len (l2input_main.bd_configs);
797     }
798   else
799     {
800       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
801       if (p == 0)
802         return;
803
804       bd_index = p[0];
805       vec_validate (l2input_main.bd_configs, bd_index);
806       start = bd_index;
807       end = start + 1;
808     }
809
810   for (bd_index = start; bd_index < end; bd_index++)
811     {
812       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
813       if (bd_is_valid (bd_config))
814         {
815           ip4_address_t ip4_addr;
816           ip6_address_t *ip6_addr;
817           u64 mac_addr;
818           bd_id = bd_config->bd_id;
819
820          /* *INDENT-OFF* */
821          hash_foreach (ip4_addr.as_u32, mac_addr, bd_config->mac_by_ip4,
822          ({
823             send_bd_ip_mac_entry (am, reg, bd_id, 0, (u8 *) &(ip4_addr.as_u8), (u8 *) &mac_addr, mp->context);
824          }));
825
826          hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6,
827          ({
828             send_bd_ip_mac_entry (am, reg, bd_id, 1, (u8 *) &(ip6_addr->as_u8), (u8 *) &mac_addr, mp->context);
829          }));
830          /* *INDENT-ON* */
831         }
832     }
833 }
834
835 static void
836 vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp)
837 {
838   bd_main_t *bdm = &bd_main;
839   vl_api_bd_ip_mac_add_del_reply_t *rmp;
840   int rv = 0;
841   u32 bd_id = ntohl (mp->bd_id);
842   u32 bd_index;
843   uword *p;
844
845   if (bd_id == 0)
846     {
847       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
848       goto out;
849     }
850
851   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
852   if (p == 0)
853     {
854       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
855       goto out;
856     }
857
858   bd_index = p[0];
859   if (bd_add_del_ip_mac (bd_index, mp->ip_address,
860                          mp->mac_address, mp->is_ipv6, mp->is_add))
861     rv = VNET_API_ERROR_UNSPECIFIED;
862
863 out:
864   REPLY_MACRO (VL_API_BD_IP_MAC_ADD_DEL_REPLY);
865 }
866
867 extern void l2_efp_filter_configure (vnet_main_t * vnet_main,
868                                      u32 sw_if_index, u8 enable);
869
870 static void
871 vl_api_l2_interface_efp_filter_t_handler (vl_api_l2_interface_efp_filter_t *
872                                           mp)
873 {
874   int rv;
875   vl_api_l2_interface_efp_filter_reply_t *rmp;
876   vnet_main_t *vnm = vnet_get_main ();
877
878   VALIDATE_SW_IF_INDEX (mp);
879
880   // enable/disable the feature
881   l2_efp_filter_configure (vnm, ntohl (mp->sw_if_index), mp->enable_disable);
882   rv = vnm->api_errno;
883
884   BAD_SW_IF_INDEX_LABEL;
885   REPLY_MACRO (VL_API_L2_INTERFACE_EFP_FILTER_REPLY);
886 }
887
888 static void
889 vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp)
890 {
891   extern int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
892                                     int is_add);
893   vl_api_l2_patch_add_del_reply_t *rmp;
894   int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
895                              int is_add);
896   int rv = 0;
897
898   VALIDATE_RX_SW_IF_INDEX (mp);
899   VALIDATE_TX_SW_IF_INDEX (mp);
900
901   rv = vnet_l2_patch_add_del (ntohl (mp->rx_sw_if_index),
902                               ntohl (mp->tx_sw_if_index),
903                               (int) (mp->is_add != 0));
904
905   BAD_RX_SW_IF_INDEX_LABEL;
906   BAD_TX_SW_IF_INDEX_LABEL;
907
908   REPLY_MACRO (VL_API_L2_PATCH_ADD_DEL_REPLY);
909 }
910
911 static void
912 vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t * mp)
913 {
914   vl_api_sw_interface_set_vpath_reply_t *rmp;
915   int rv = 0;
916   u32 sw_if_index = ntohl (mp->sw_if_index);
917
918   VALIDATE_SW_IF_INDEX (mp);
919
920   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VPATH, mp->enable);
921   vnet_feature_enable_disable ("ip4-unicast", "vpath-input-ip4",
922                                sw_if_index, mp->enable, 0, 0);
923   vnet_feature_enable_disable ("ip4-multicast", "vpath-input-ip4",
924                                sw_if_index, mp->enable, 0, 0);
925   vnet_feature_enable_disable ("ip6-unicast", "vpath-input-ip6",
926                                sw_if_index, mp->enable, 0, 0);
927   vnet_feature_enable_disable ("ip6-multicast", "vpath-input-ip6",
928                                sw_if_index, mp->enable, 0, 0);
929
930   BAD_SW_IF_INDEX_LABEL;
931
932   REPLY_MACRO (VL_API_SW_INTERFACE_SET_VPATH_REPLY);
933 }
934
935 /*
936  * l2_api_hookup
937  * Add vpe's API message handlers to the table.
938  * vlib has already mapped shared memory and
939  * added the client registration handlers.
940  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
941  */
942 #define vl_msg_name_crc_list
943 #include <vnet/vnet_all_api_h.h>
944 #undef vl_msg_name_crc_list
945
946 static void
947 setup_message_id_table (api_main_t * am)
948 {
949 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
950   foreach_vl_msg_name_crc_l2;
951 #undef _
952 }
953
954 static clib_error_t *
955 l2_api_hookup (vlib_main_t * vm)
956 {
957   api_main_t *am = &api_main;
958
959 #define _(N,n)                                                  \
960     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
961                            vl_api_##n##_t_handler,              \
962                            vl_noop_handler,                     \
963                            vl_api_##n##_t_endian,               \
964                            vl_api_##n##_t_print,                \
965                            sizeof(vl_api_##n##_t), 1);
966   foreach_vpe_api_msg;
967 #undef _
968
969   /*
970    * Set up the (msg_name, crc, message-id) table
971    */
972   setup_message_id_table (am);
973
974   return 0;
975 }
976
977 VLIB_API_INIT_FUNCTION (l2_api_hookup);
978
979 /*
980  * fd.io coding-style-patch-verification: ON
981  *
982  * Local Variables:
983  * eval: (c-set-style "gnu")
984  * End:
985  */