l2: add api test file
[vpp.git] / src / vnet / l2 / l2_test.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright(c) 2021 Cisco Systems, Inc.
3  */
4
5 #include <vat/vat.h>
6 #include <vlibapi/api.h>
7 #include <vlibmemory/api.h>
8 #include <vppinfra/error.h>
9 #include <vpp/api/types.h>
10 #include <inttypes.h>
11
12 #include <vnet/l2/l2_classify.h>
13 #include <vnet/l2/l2_vtr.h>
14 #include <vnet/ip/ip_types_api.h>
15
16 #define __plugin_msg_base l2_test_main.msg_id_base
17 #include <vlibapi/vat_helper_macros.h>
18
19 #include <vlibmemory/vlib.api_enum.h>
20 #include <vlibmemory/vlib.api_types.h>
21
22 /* Declare message IDs */
23 #include <vnet/format_fns.h>
24 #include <vnet/l2/l2.api_enum.h>
25 #include <vnet/l2/l2.api_types.h>
26
27 #define vl_endianfun /* define message structures */
28 #include <vnet/l2/l2.api.h>
29 #undef vl_endianfun
30
31 typedef struct
32 {
33   /* API message ID base */
34   u16 msg_id_base;
35   u32 ping_id;
36   vat_main_t *vat_main;
37 } l2_test_main_t;
38
39 static l2_test_main_t l2_test_main;
40
41 static void
42 vl_api_l2_fib_table_details_t_handler (vl_api_l2_fib_table_details_t *mp)
43 {
44   vat_main_t *vam = l2_test_main.vat_main;
45
46   fformat (
47     vam->ofp, "%3" PRIu32 "    %U    %3" PRIu32 "       %d       %d     %d",
48     ntohl (mp->bd_id), format_ethernet_address, mp->mac,
49     ntohl (mp->sw_if_index), mp->static_mac, mp->filter_mac, mp->bvi_mac);
50 }
51
52 static int
53 api_l2_fib_table_dump (vat_main_t *vam)
54 {
55   unformat_input_t *i = vam->input;
56   vl_api_l2_fib_table_dump_t *mp;
57   vl_api_control_ping_t *mp_ping;
58   u32 bd_id;
59   u8 bd_id_set = 0;
60   int ret;
61
62   /* Parse args required to build the message */
63   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
64     {
65       if (unformat (i, "bd_id %d", &bd_id))
66         bd_id_set = 1;
67       else
68         break;
69     }
70
71   if (bd_id_set == 0)
72     {
73       errmsg ("missing bridge domain");
74       return -99;
75     }
76
77   fformat (vam->ofp, "BD-ID     Mac Address      sw-ndx  Static  Filter  BVI");
78
79   /* Get list of l2 fib entries */
80   M (L2_FIB_TABLE_DUMP, mp);
81
82   mp->bd_id = ntohl (bd_id);
83   S (mp);
84
85   /* Use a control ping for synchronization */
86   PING (&l2_test_main, mp_ping);
87   S (mp_ping);
88
89   W (ret);
90   return ret;
91 }
92
93 static void
94 vl_api_l2_xconnect_details_t_handler (vl_api_l2_xconnect_details_t *mp)
95 {
96   vat_main_t *vam = l2_test_main.vat_main;
97   fformat (vam->ofp, "%15d%15d", ntohl (mp->rx_sw_if_index),
98            ntohl (mp->tx_sw_if_index));
99 }
100
101 static int
102 api_l2_xconnect_dump (vat_main_t *vam)
103 {
104   vl_api_l2_xconnect_dump_t *mp;
105   vl_api_control_ping_t *mp_ping;
106   int ret;
107
108   if (!vam->json_output)
109     {
110       print (vam->ofp, "%15s%15s", "rx_sw_if_index", "tx_sw_if_index");
111     }
112
113   M (L2_XCONNECT_DUMP, mp);
114
115   S (mp);
116
117   /* Use a control ping for synchronization */
118   PING (&l2_test_main, mp_ping);
119   S (mp_ping);
120
121   W (ret);
122   return ret;
123 }
124
125 static int
126 api_want_l2_arp_term_events (vat_main_t *vam)
127 {
128   return -1;
129 }
130
131 static int
132 api_want_l2_macs_events (vat_main_t *vam)
133 {
134   unformat_input_t *line_input = vam->input;
135   vl_api_want_l2_macs_events_t *mp;
136   u8 enable_disable = 1;
137   u32 scan_delay = 0;
138   u32 max_macs_in_event = 0;
139   u32 learn_limit = 0;
140   int ret;
141
142   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
143     {
144       if (unformat (line_input, "learn-limit %d", &learn_limit))
145         ;
146       else if (unformat (line_input, "scan-delay %d", &scan_delay))
147         ;
148       else if (unformat (line_input, "max-entries %d", &max_macs_in_event))
149         ;
150       else if (unformat (line_input, "disable"))
151         enable_disable = 0;
152       else
153         break;
154     }
155
156   M (WANT_L2_MACS_EVENTS, mp);
157   mp->enable_disable = enable_disable;
158   mp->pid = htonl (getpid ());
159   mp->learn_limit = htonl (learn_limit);
160   mp->scan_delay = (u8) scan_delay;
161   mp->max_macs_in_event = (u8) (max_macs_in_event / 10);
162   S (mp);
163   W (ret);
164   return ret;
165 }
166
167 static int
168 api_l2fib_flush_all (vat_main_t *vam)
169 {
170   return -1;
171 }
172
173 static void
174 increment_mac_address (u8 *mac)
175 {
176   u64 tmp = *((u64 *) mac);
177   tmp = clib_net_to_host_u64 (tmp);
178   tmp += 1 << 16; /* skip unused (least significant) octets */
179   tmp = clib_host_to_net_u64 (tmp);
180
181   clib_memcpy (mac, &tmp, 6);
182 }
183
184 static int
185 api_l2fib_add_del (vat_main_t *vam)
186 {
187   vnet_main_t *vnm = vnet_get_main ();
188   unformat_input_t *i = vam->input;
189   vl_api_l2fib_add_del_t *mp;
190   f64 timeout;
191   u8 mac[6] = { 0 };
192   u8 mac_set = 0;
193   u32 bd_id;
194   u8 bd_id_set = 0;
195   u32 sw_if_index = 0;
196   u8 sw_if_index_set = 0;
197   u8 is_add = 1;
198   u8 static_mac = 0;
199   u8 filter_mac = 0;
200   u8 bvi_mac = 0;
201   int count = 1;
202   f64 before = 0;
203   int j;
204
205   /* Parse args required to build the message */
206   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
207     {
208       if (unformat (i, "mac %U", unformat_ethernet_address, mac))
209         mac_set = 1;
210       else if (unformat (i, "bd_id %d", &bd_id))
211         bd_id_set = 1;
212       else if (unformat (i, "sw_if_index %d", &sw_if_index))
213         sw_if_index_set = 1;
214       else if (unformat (i, "sw_if"))
215         {
216           if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
217             {
218               if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
219                             &sw_if_index))
220                 sw_if_index_set = 1;
221             }
222           else
223             break;
224         }
225       else if (unformat (i, "static"))
226         static_mac = 1;
227       else if (unformat (i, "filter"))
228         {
229           filter_mac = 1;
230           static_mac = 1;
231         }
232       else if (unformat (i, "bvi"))
233         {
234           bvi_mac = 1;
235           static_mac = 1;
236         }
237       else if (unformat (i, "del"))
238         is_add = 0;
239       else if (unformat (i, "count %d", &count))
240         ;
241       else
242         break;
243     }
244
245   if (mac_set == 0)
246     {
247       errmsg ("missing mac address");
248       return -99;
249     }
250
251   if (bd_id_set == 0)
252     {
253       errmsg ("missing bridge domain");
254       return -99;
255     }
256
257   if (is_add && sw_if_index_set == 0 && filter_mac == 0)
258     {
259       errmsg ("missing interface name or sw_if_index");
260       return -99;
261     }
262
263   if (count > 1)
264     {
265       /* Turn on async mode */
266       vam->async_mode = 1;
267       vam->async_errors = 0;
268       before = vat_time_now (vam);
269     }
270
271   for (j = 0; j < count; j++)
272     {
273       M (L2FIB_ADD_DEL, mp);
274
275       clib_memcpy (mp->mac, mac, 6);
276       mp->bd_id = ntohl (bd_id);
277       mp->is_add = is_add;
278       mp->sw_if_index = ntohl (sw_if_index);
279
280       if (is_add)
281         {
282           mp->static_mac = static_mac;
283           mp->filter_mac = filter_mac;
284           mp->bvi_mac = bvi_mac;
285         }
286       increment_mac_address (mac);
287       /* send it... */
288       S (mp);
289     }
290
291   if (count > 1)
292     {
293       vl_api_control_ping_t *mp_ping;
294       f64 after;
295
296       /* Shut off async mode */
297       vam->async_mode = 0;
298
299       PING (&l2_test_main, mp_ping);
300       S (mp_ping);
301
302       timeout = vat_time_now (vam) + 1.0;
303       while (vat_time_now (vam) < timeout)
304         if (vam->result_ready == 1)
305           goto out;
306       vam->retval = -99;
307
308     out:
309       if (vam->retval == -99)
310         errmsg ("timeout");
311
312       if (vam->async_errors > 0)
313         {
314           errmsg ("%d asynchronous errors", vam->async_errors);
315           vam->retval = -98;
316         }
317       vam->async_errors = 0;
318       after = vat_time_now (vam);
319
320       print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", count,
321              after - before, count / (after - before));
322     }
323   else
324     {
325       int ret;
326
327       /* Wait for a reply... */
328       W (ret);
329       return ret;
330     }
331   /* Return the good/bad news */
332   return (vam->retval);
333 }
334
335 static int
336 api_l2fib_flush_int (vat_main_t *vam)
337 {
338   vnet_main_t *vnm = vnet_get_main ();
339   unformat_input_t *i = vam->input;
340   vl_api_l2fib_flush_int_t *mp;
341   u32 sw_if_index = ~0;
342   int ret;
343
344   /* Parse args required to build the message */
345   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
346     {
347       if (unformat (i, "sw_if_index %d", &sw_if_index))
348         ;
349       else if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
350                          &sw_if_index))
351         ;
352       else
353         break;
354     }
355
356   if (sw_if_index == ~0)
357     {
358       errmsg ("missing interface name or sw_if_index");
359       return -99;
360     }
361
362   M (L2FIB_FLUSH_INT, mp);
363
364   mp->sw_if_index = ntohl (sw_if_index);
365
366   S (mp);
367   W (ret);
368   return ret;
369 }
370
371 static int
372 api_l2_fib_clear_table (vat_main_t *vam)
373 {
374   vl_api_l2_fib_clear_table_t *mp;
375   int ret;
376
377   M (L2_FIB_CLEAR_TABLE, mp);
378
379   S (mp);
380   W (ret);
381   return ret;
382 }
383
384 static int
385 api_bridge_domain_set_mac_age (vat_main_t *vam)
386 {
387   unformat_input_t *i = vam->input;
388   vl_api_bridge_domain_set_mac_age_t *mp;
389   u32 bd_id = ~0;
390   u32 mac_age = 0;
391   int ret;
392
393   /* Parse args required to build the message */
394   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
395     {
396       if (unformat (i, "bd_id %d", &bd_id))
397         ;
398       else if (unformat (i, "mac-age %d", &mac_age))
399         ;
400       else
401         break;
402     }
403
404   if (bd_id == ~0)
405     {
406       errmsg ("missing bridge domain");
407       return -99;
408     }
409
410   if (mac_age > 255)
411     {
412       errmsg ("mac age must be less than 256 ");
413       return -99;
414     }
415
416   M (BRIDGE_DOMAIN_SET_MAC_AGE, mp);
417
418   mp->bd_id = htonl (bd_id);
419   mp->mac_age = (u8) mac_age;
420
421   S (mp);
422   W (ret);
423   return ret;
424 }
425
426 static int
427 api_l2fib_set_scan_delay (vat_main_t *vam)
428 {
429   return -1;
430 }
431
432 static int
433 api_want_l2_macs_events2 (vat_main_t *vam)
434 {
435   return -1;
436 }
437
438 static int
439 api_l2_flags (vat_main_t *vam)
440 {
441   vnet_main_t *vnm = vnet_get_main ();
442   unformat_input_t *i = vam->input;
443   vl_api_l2_flags_t *mp;
444   u32 sw_if_index;
445   u32 flags = 0;
446   u8 sw_if_index_set = 0;
447   u8 is_set = 0;
448   int ret;
449
450   /* Parse args required to build the message */
451   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
452     {
453       if (unformat (i, "sw_if_index %d", &sw_if_index))
454         sw_if_index_set = 1;
455       else if (unformat (i, "sw_if"))
456         {
457           if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
458             {
459               if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
460                             &sw_if_index))
461                 sw_if_index_set = 1;
462             }
463           else
464             break;
465         }
466       else if (unformat (i, "learn"))
467         flags |= L2_LEARN;
468       else if (unformat (i, "forward"))
469         flags |= L2_FWD;
470       else if (unformat (i, "flood"))
471         flags |= L2_FLOOD;
472       else if (unformat (i, "uu-flood"))
473         flags |= L2_UU_FLOOD;
474       else if (unformat (i, "arp-term"))
475         flags |= L2_ARP_TERM;
476       else if (unformat (i, "off"))
477         is_set = 0;
478       else if (unformat (i, "disable"))
479         is_set = 0;
480       else
481         break;
482     }
483
484   if (sw_if_index_set == 0)
485     {
486       errmsg ("missing interface name or sw_if_index");
487       return -99;
488     }
489
490   M (L2_FLAGS, mp);
491
492   mp->sw_if_index = ntohl (sw_if_index);
493   mp->feature_bitmap = ntohl (flags);
494   mp->is_set = is_set;
495
496   S (mp);
497   W (ret);
498   return ret;
499 }
500
501 static void
502 vl_api_l2_flags_reply_t_handler (vl_api_l2_flags_reply_t *mp)
503 {
504   vat_main_t *vam = l2_test_main.vat_main;
505   i32 retval = ntohl (mp->retval);
506   if (vam->async_mode)
507     {
508       vam->async_errors += (retval < 0);
509     }
510   else
511     {
512       vam->retval = retval;
513       vam->result_ready = 1;
514     }
515 }
516
517 static int
518 api_l2fib_flush_bd (vat_main_t *vam)
519 {
520   unformat_input_t *i = vam->input;
521   vl_api_l2fib_flush_bd_t *mp;
522   u32 bd_id = ~0;
523   int ret;
524
525   /* Parse args required to build the message */
526   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
527     {
528       if (unformat (i, "bd_id %d", &bd_id))
529         ;
530       else
531         break;
532     }
533
534   if (bd_id == ~0)
535     {
536       errmsg ("missing bridge domain");
537       return -99;
538     }
539
540   M (L2FIB_FLUSH_BD, mp);
541
542   mp->bd_id = htonl (bd_id);
543
544   S (mp);
545   W (ret);
546   return ret;
547 }
548
549 static int
550 api_bridge_domain_add_del (vat_main_t *vam)
551 {
552   unformat_input_t *i = vam->input;
553   vl_api_bridge_domain_add_del_t *mp;
554   u32 bd_id = ~0;
555   u8 is_add = 1;
556   u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0;
557   u8 *bd_tag = NULL;
558   u32 mac_age = 0;
559   int ret;
560
561   /* Parse args required to build the message */
562   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
563     {
564       if (unformat (i, "bd_id %d", &bd_id))
565         ;
566       else if (unformat (i, "flood %d", &flood))
567         ;
568       else if (unformat (i, "uu-flood %d", &uu_flood))
569         ;
570       else if (unformat (i, "forward %d", &forward))
571         ;
572       else if (unformat (i, "learn %d", &learn))
573         ;
574       else if (unformat (i, "arp-term %d", &arp_term))
575         ;
576       else if (unformat (i, "mac-age %d", &mac_age))
577         ;
578       else if (unformat (i, "bd-tag %s", &bd_tag))
579         ;
580       else if (unformat (i, "del"))
581         {
582           is_add = 0;
583           flood = uu_flood = forward = learn = 0;
584         }
585       else
586         break;
587     }
588
589   if (bd_id == ~0)
590     {
591       errmsg ("missing bridge domain");
592       ret = -99;
593       goto done;
594     }
595
596   if (mac_age > 255)
597     {
598       errmsg ("mac age must be less than 256 ");
599       ret = -99;
600       goto done;
601     }
602
603   if ((bd_tag) && (vec_len (bd_tag) > 63))
604     {
605       errmsg ("bd-tag cannot be longer than 63");
606       ret = -99;
607       goto done;
608     }
609
610   M (BRIDGE_DOMAIN_ADD_DEL, mp);
611
612   mp->bd_id = ntohl (bd_id);
613   mp->flood = flood;
614   mp->uu_flood = uu_flood;
615   mp->forward = forward;
616   mp->learn = learn;
617   mp->arp_term = arp_term;
618   mp->is_add = is_add;
619   mp->mac_age = (u8) mac_age;
620   if (bd_tag)
621     {
622       clib_memcpy (mp->bd_tag, bd_tag, vec_len (bd_tag));
623       mp->bd_tag[vec_len (bd_tag)] = 0;
624     }
625   S (mp);
626   W (ret);
627
628 done:
629   vec_free (bd_tag);
630   return ret;
631 }
632
633 #define foreach_pbb_vtr_op                                                    \
634   _ ("disable", L2_VTR_DISABLED)                                              \
635   _ ("pop", L2_VTR_POP_2)                                                     \
636   _ ("push", L2_VTR_PUSH_2)
637
638 static int
639 api_l2_interface_pbb_tag_rewrite (vat_main_t *vam)
640 {
641   vnet_main_t *vnm = vnet_get_main ();
642   unformat_input_t *i = vam->input;
643   vl_api_l2_interface_pbb_tag_rewrite_t *mp;
644   u32 sw_if_index = ~0, vtr_op = ~0;
645   u16 outer_tag = ~0;
646   u8 dmac[6], smac[6];
647   u8 dmac_set = 0, smac_set = 0;
648   u16 vlanid = 0;
649   u32 sid = ~0;
650   u32 tmp;
651   int ret;
652
653   /* Shut up coverity */
654   clib_memset (dmac, 0, sizeof (dmac));
655   clib_memset (smac, 0, sizeof (smac));
656
657   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
658     {
659       if (unformat (i, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
660         ;
661       else if (unformat (i, "sw_if_index %d", &sw_if_index))
662         ;
663       else if (unformat (i, "vtr_op %d", &vtr_op))
664         ;
665 #define _(n, v)                                                               \
666   else if (unformat (i, n)) { vtr_op = v; }
667       foreach_pbb_vtr_op
668 #undef _
669         else if (unformat (i, "translate_pbb_stag"))
670       {
671         if (unformat (i, "%d", &tmp))
672           {
673             vtr_op = L2_VTR_TRANSLATE_2_1;
674             outer_tag = tmp;
675           }
676         else
677           {
678             errmsg (
679               "translate_pbb_stag operation requires outer tag definition");
680             return -99;
681           }
682       }
683       else if (unformat (i, "dmac %U", unformat_ethernet_address, dmac))
684         dmac_set++;
685       else if (unformat (i, "smac %U", unformat_ethernet_address, smac))
686         smac_set++;
687       else if (unformat (i, "sid %d", &sid));
688       else if (unformat (i, "vlanid %d", &tmp)) vlanid = tmp;
689       else
690       {
691         clib_warning ("parse error '%U'", format_unformat_error, i);
692         return -99;
693       }
694     }
695
696   if ((sw_if_index == ~0) || (vtr_op == ~0))
697     {
698       errmsg ("missing sw_if_index or vtr operation");
699       return -99;
700     }
701   if (((vtr_op == L2_VTR_PUSH_2) || (vtr_op == L2_VTR_TRANSLATE_2_2)) &&
702       ((dmac_set == 0) || (smac_set == 0) || (sid == ~0)))
703     {
704       errmsg ("push and translate_qinq operations require dmac, smac, sid and "
705               "optionally vlanid");
706       return -99;
707     }
708
709   M (L2_INTERFACE_PBB_TAG_REWRITE, mp);
710   mp->sw_if_index = ntohl (sw_if_index);
711   mp->vtr_op = ntohl (vtr_op);
712   mp->outer_tag = ntohs (outer_tag);
713   clib_memcpy (mp->b_dmac, dmac, sizeof (dmac));
714   clib_memcpy (mp->b_smac, smac, sizeof (smac));
715   mp->b_vlanid = ntohs (vlanid);
716   mp->i_sid = ntohl (sid);
717
718   S (mp);
719   W (ret);
720   return ret;
721 }
722
723 static int
724 api_sw_interface_set_l2_xconnect (vat_main_t *vam)
725 {
726   vnet_main_t *vnm = vnet_get_main ();
727   unformat_input_t *i = vam->input;
728   vl_api_sw_interface_set_l2_xconnect_t *mp;
729   u32 rx_sw_if_index;
730   u8 rx_sw_if_index_set = 0;
731   u32 tx_sw_if_index;
732   u8 tx_sw_if_index_set = 0;
733   u8 enable = 1;
734   int ret;
735
736   /* Parse args required to build the message */
737   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
738     {
739       if (unformat (i, "rx_sw_if_index %d", &rx_sw_if_index))
740         rx_sw_if_index_set = 1;
741       else if (unformat (i, "tx_sw_if_index %d", &tx_sw_if_index))
742         tx_sw_if_index_set = 1;
743       else if (unformat (i, "rx"))
744         {
745           if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
746             {
747               if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
748                             &rx_sw_if_index))
749                 rx_sw_if_index_set = 1;
750             }
751           else
752             break;
753         }
754       else if (unformat (i, "tx"))
755         {
756           if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
757             {
758               if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
759                             &tx_sw_if_index))
760                 tx_sw_if_index_set = 1;
761             }
762           else
763             break;
764         }
765       else if (unformat (i, "enable"))
766         enable = 1;
767       else if (unformat (i, "disable"))
768         enable = 0;
769       else
770         break;
771     }
772
773   if (rx_sw_if_index_set == 0)
774     {
775       errmsg ("missing rx interface name or rx_sw_if_index");
776       return -99;
777     }
778
779   if (enable && (tx_sw_if_index_set == 0))
780     {
781       errmsg ("missing tx interface name or tx_sw_if_index");
782       return -99;
783     }
784
785   M (SW_INTERFACE_SET_L2_XCONNECT, mp);
786
787   mp->rx_sw_if_index = ntohl (rx_sw_if_index);
788   mp->tx_sw_if_index = ntohl (tx_sw_if_index);
789   mp->enable = enable;
790
791   S (mp);
792   W (ret);
793   return ret;
794 }
795
796 static int
797 api_l2_interface_efp_filter (vat_main_t *vam)
798 {
799   vnet_main_t *vnm = vnet_get_main ();
800   unformat_input_t *i = vam->input;
801   vl_api_l2_interface_efp_filter_t *mp;
802   u32 sw_if_index;
803   u8 enable = 1;
804   u8 sw_if_index_set = 0;
805   int ret;
806
807   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
808     {
809       if (unformat (i, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
810         sw_if_index_set = 1;
811       else if (unformat (i, "sw_if_index %d", &sw_if_index))
812         sw_if_index_set = 1;
813       else if (unformat (i, "enable"))
814         enable = 1;
815       else if (unformat (i, "disable"))
816         enable = 0;
817       else
818         {
819           clib_warning ("parse error '%U'", format_unformat_error, i);
820           return -99;
821         }
822     }
823
824   if (sw_if_index_set == 0)
825     {
826       errmsg ("missing sw_if_index");
827       return -99;
828     }
829
830   M (L2_INTERFACE_EFP_FILTER, mp);
831
832   mp->sw_if_index = ntohl (sw_if_index);
833   mp->enable_disable = enable;
834
835   S (mp);
836   W (ret);
837   return ret;
838 }
839
840 static void
841 vl_api_bd_ip_mac_details_t_handler (vl_api_bd_ip_mac_details_t *mp)
842 {
843   vat_main_t *vam = &vat_main;
844
845   print (vam->ofp, "\n%-5d %U %U", ntohl (mp->entry.bd_id),
846          format_vl_api_mac_address, mp->entry.mac, format_vl_api_address,
847          &mp->entry.ip);
848 }
849
850 static void
851 vl_api_bvi_create_reply_t_handler (vl_api_bvi_create_reply_t *mp)
852 {
853 }
854
855 static int
856 api_sw_interface_set_l2_bridge (vat_main_t *vam)
857 {
858   vnet_main_t *vnm = vnet_get_main ();
859   unformat_input_t *i = vam->input;
860   vl_api_sw_interface_set_l2_bridge_t *mp;
861   vl_api_l2_port_type_t port_type;
862   u32 rx_sw_if_index;
863   u8 rx_sw_if_index_set = 0;
864   u32 bd_id;
865   u8 bd_id_set = 0;
866   u32 shg = 0;
867   u8 enable = 1;
868   int ret;
869
870   port_type = L2_API_PORT_TYPE_NORMAL;
871
872   /* Parse args required to build the message */
873   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
874     {
875       if (unformat (i, "sw_if_index %d", &rx_sw_if_index))
876         rx_sw_if_index_set = 1;
877       else if (unformat (i, "bd_id %d", &bd_id))
878         bd_id_set = 1;
879       else if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
880                          &rx_sw_if_index))
881         rx_sw_if_index_set = 1;
882       else if (unformat (i, "shg %d", &shg))
883         ;
884       else if (unformat (i, "bvi"))
885         port_type = L2_API_PORT_TYPE_BVI;
886       else if (unformat (i, "uu-fwd"))
887         port_type = L2_API_PORT_TYPE_UU_FWD;
888       else if (unformat (i, "enable"))
889         enable = 1;
890       else if (unformat (i, "disable"))
891         enable = 0;
892       else
893         break;
894     }
895
896   if (rx_sw_if_index_set == 0)
897     {
898       errmsg ("missing rx interface name or sw_if_index");
899       return -99;
900     }
901
902   if (enable && (bd_id_set == 0))
903     {
904       errmsg ("missing bridge domain");
905       return -99;
906     }
907
908   M (SW_INTERFACE_SET_L2_BRIDGE, mp);
909
910   mp->rx_sw_if_index = ntohl (rx_sw_if_index);
911   mp->bd_id = ntohl (bd_id);
912   mp->shg = (u8) shg;
913   mp->port_type = ntohl (port_type);
914   mp->enable = enable;
915
916   S (mp);
917   W (ret);
918   return ret;
919 }
920
921 static int
922 api_sw_interface_set_vpath (vat_main_t *vam)
923 {
924   vnet_main_t *vnm = vnet_get_main ();
925   unformat_input_t *i = vam->input;
926   vl_api_sw_interface_set_vpath_t *mp;
927   u32 sw_if_index = 0;
928   u8 sw_if_index_set = 0;
929   u8 is_enable = 0;
930   int ret;
931
932   /* Parse args required to build the message */
933   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
934     {
935       if (unformat (i, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
936         sw_if_index_set = 1;
937       else if (unformat (i, "sw_if_index %d", &sw_if_index))
938         sw_if_index_set = 1;
939       else if (unformat (i, "enable"))
940         is_enable = 1;
941       else if (unformat (i, "disable"))
942         is_enable = 0;
943       else
944         break;
945     }
946
947   if (sw_if_index_set == 0)
948     {
949       errmsg ("missing interface name or sw_if_index");
950       return -99;
951     }
952
953   /* Construct the API message */
954   M (SW_INTERFACE_SET_VPATH, mp);
955
956   mp->sw_if_index = ntohl (sw_if_index);
957   mp->enable = is_enable;
958
959   /* send it... */
960   S (mp);
961
962   /* Wait for a reply... */
963   W (ret);
964   return ret;
965 }
966
967 static int
968 api_l2_patch_add_del (vat_main_t *vam)
969 {
970   vnet_main_t *vnm = vnet_get_main ();
971   unformat_input_t *i = vam->input;
972   vl_api_l2_patch_add_del_t *mp;
973   u32 rx_sw_if_index;
974   u8 rx_sw_if_index_set = 0;
975   u32 tx_sw_if_index;
976   u8 tx_sw_if_index_set = 0;
977   u8 is_add = 1;
978   int ret;
979
980   /* Parse args required to build the message */
981   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
982     {
983       if (unformat (i, "rx_sw_if_index %d", &rx_sw_if_index))
984         rx_sw_if_index_set = 1;
985       else if (unformat (i, "tx_sw_if_index %d", &tx_sw_if_index))
986         tx_sw_if_index_set = 1;
987       else if (unformat (i, "rx"))
988         {
989           if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
990             {
991               if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
992                             &rx_sw_if_index))
993                 rx_sw_if_index_set = 1;
994             }
995           else
996             break;
997         }
998       else if (unformat (i, "tx"))
999         {
1000           if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1001             {
1002               if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
1003                             &tx_sw_if_index))
1004                 tx_sw_if_index_set = 1;
1005             }
1006           else
1007             break;
1008         }
1009       else if (unformat (i, "del"))
1010         is_add = 0;
1011       else
1012         break;
1013     }
1014
1015   if (rx_sw_if_index_set == 0)
1016     {
1017       errmsg ("missing rx interface name or rx_sw_if_index");
1018       return -99;
1019     }
1020
1021   if (tx_sw_if_index_set == 0)
1022     {
1023       errmsg ("missing tx interface name or tx_sw_if_index");
1024       return -99;
1025     }
1026
1027   M (L2_PATCH_ADD_DEL, mp);
1028
1029   mp->rx_sw_if_index = ntohl (rx_sw_if_index);
1030   mp->tx_sw_if_index = ntohl (tx_sw_if_index);
1031   mp->is_add = is_add;
1032
1033   S (mp);
1034   W (ret);
1035   return ret;
1036 }
1037
1038 static void
1039 vl_api_bridge_flags_reply_t_handler (vl_api_bridge_flags_reply_t *mp)
1040 {
1041   vat_main_t *vam = &vat_main;
1042   i32 retval = ntohl (mp->retval);
1043   if (vam->async_mode)
1044     {
1045       vam->async_errors += (retval < 0);
1046     }
1047   else
1048     {
1049       vam->retval = retval;
1050       vam->result_ready = 1;
1051     }
1052 }
1053
1054 #define foreach_vtr_op                                                        \
1055   _ ("disable", L2_VTR_DISABLED)                                              \
1056   _ ("push-1", L2_VTR_PUSH_1)                                                 \
1057   _ ("push-2", L2_VTR_PUSH_2)                                                 \
1058   _ ("pop-1", L2_VTR_POP_1)                                                   \
1059   _ ("pop-2", L2_VTR_POP_2)                                                   \
1060   _ ("translate-1-1", L2_VTR_TRANSLATE_1_1)                                   \
1061   _ ("translate-1-2", L2_VTR_TRANSLATE_1_2)                                   \
1062   _ ("translate-2-1", L2_VTR_TRANSLATE_2_1)                                   \
1063   _ ("translate-2-2", L2_VTR_TRANSLATE_2_2)
1064
1065 static int
1066 api_l2_interface_vlan_tag_rewrite (vat_main_t *vam)
1067 {
1068   vnet_main_t *vnm = vnet_get_main ();
1069   unformat_input_t *i = vam->input;
1070   vl_api_l2_interface_vlan_tag_rewrite_t *mp;
1071   u32 sw_if_index;
1072   u8 sw_if_index_set = 0;
1073   u8 vtr_op_set = 0;
1074   u32 vtr_op = 0;
1075   u32 push_dot1q = 1;
1076   u32 tag1 = ~0;
1077   u32 tag2 = ~0;
1078   int ret;
1079
1080   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1081     {
1082       if (unformat (i, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1083         sw_if_index_set = 1;
1084       else if (unformat (i, "sw_if_index %d", &sw_if_index))
1085         sw_if_index_set = 1;
1086       else if (unformat (i, "vtr_op %d", &vtr_op))
1087         vtr_op_set = 1;
1088 #define _(n, v)                                                               \
1089   else if (unformat (i, n))                                                   \
1090   {                                                                           \
1091     vtr_op = v;                                                               \
1092     vtr_op_set = 1;                                                           \
1093   }
1094       foreach_vtr_op
1095 #undef _
1096         else if (unformat (i, "push_dot1q %d", &push_dot1q));
1097       else if (unformat (i, "tag1 %d", &tag1));
1098       else if (unformat (i, "tag2 %d", &tag2));
1099       else
1100       {
1101         clib_warning ("parse error '%U'", format_unformat_error, i);
1102         return -99;
1103       }
1104     }
1105
1106   if ((sw_if_index_set == 0) || (vtr_op_set == 0))
1107     {
1108       errmsg ("missing vtr operation or sw_if_index");
1109       return -99;
1110     }
1111
1112   M (L2_INTERFACE_VLAN_TAG_REWRITE, mp);
1113   mp->sw_if_index = ntohl (sw_if_index);
1114   mp->vtr_op = ntohl (vtr_op);
1115   mp->push_dot1q = ntohl (push_dot1q);
1116   mp->tag1 = ntohl (tag1);
1117   mp->tag2 = ntohl (tag2);
1118
1119   S (mp);
1120   W (ret);
1121   return ret;
1122 }
1123
1124 static int
1125 api_bridge_domain_set_learn_limit (vat_main_t *vam)
1126 {
1127   return -1;
1128 }
1129
1130 static int
1131 api_bd_ip_mac_add_del (vat_main_t *vam)
1132 {
1133   vl_api_address_t ip = VL_API_ZERO_ADDRESS;
1134   vl_api_mac_address_t mac = { 0 };
1135   unformat_input_t *i = vam->input;
1136   vl_api_bd_ip_mac_add_del_t *mp;
1137   u32 bd_id;
1138   u8 is_add = 1;
1139   u8 bd_id_set = 0;
1140   u8 ip_set = 0;
1141   u8 mac_set = 0;
1142   int ret;
1143
1144   /* Parse args required to build the message */
1145   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1146     {
1147       if (unformat (i, "bd_id %d", &bd_id))
1148         {
1149           bd_id_set++;
1150         }
1151       else if (unformat (i, "%U", unformat_vl_api_address, &ip))
1152         {
1153           ip_set++;
1154         }
1155       else if (unformat (i, "%U", unformat_vl_api_mac_address, &mac))
1156         {
1157           mac_set++;
1158         }
1159       else if (unformat (i, "del"))
1160         is_add = 0;
1161       else
1162         break;
1163     }
1164
1165   if (bd_id_set == 0)
1166     {
1167       errmsg ("missing bridge domain");
1168       return -99;
1169     }
1170   else if (ip_set == 0)
1171     {
1172       errmsg ("missing IP address");
1173       return -99;
1174     }
1175   else if (mac_set == 0)
1176     {
1177       errmsg ("missing MAC address");
1178       return -99;
1179     }
1180
1181   M (BD_IP_MAC_ADD_DEL, mp);
1182
1183   mp->entry.bd_id = ntohl (bd_id);
1184   mp->is_add = is_add;
1185
1186   clib_memcpy (&mp->entry.ip, &ip, sizeof (ip));
1187   clib_memcpy (&mp->entry.mac, &mac, sizeof (mac));
1188
1189   S (mp);
1190   W (ret);
1191   return ret;
1192 }
1193
1194 static void
1195 vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t *mp)
1196 {
1197   vat_main_t *vam = l2_test_main.vat_main;
1198   u32 n_sw_ifs = ntohl (mp->n_sw_ifs);
1199   int i;
1200
1201   print (vam->ofp, "\n%-3s %-3s %-3s %-3s %-3s %-6s %-3s", " ID", "LRN", "FWD",
1202          "FLD", "BVI", "UU-FWD", "#IF");
1203
1204   print (vam->ofp, "%3d %3d %3d %3d %3d %6d %3d", ntohl (mp->bd_id), mp->learn,
1205          mp->forward, mp->flood, ntohl (mp->bvi_sw_if_index),
1206          ntohl (mp->uu_fwd_sw_if_index), n_sw_ifs);
1207
1208   if (n_sw_ifs)
1209     {
1210       vl_api_bridge_domain_sw_if_t *sw_ifs;
1211       print (vam->ofp, "\n\n%s %s  %s", "sw_if_index", "SHG",
1212              "Interface Name");
1213
1214       sw_ifs = mp->sw_if_details;
1215       for (i = 0; i < n_sw_ifs; i++)
1216         {
1217           u8 *sw_if_name = 0;
1218           u32 sw_if_index;
1219           hash_pair_t *p;
1220
1221           sw_if_index = ntohl (sw_ifs->sw_if_index);
1222
1223           hash_foreach_pair (p, vam->sw_if_index_by_interface_name, ({
1224                                if ((u32) p->value[0] == sw_if_index)
1225                                  {
1226                                    sw_if_name = (u8 *) (p->key);
1227                                    break;
1228                                  }
1229                              }));
1230           print (vam->ofp, "%7d     %3d  %s", sw_if_index, sw_ifs->shg,
1231                  sw_if_name ? (char *) sw_if_name : "sw_if_index not found!");
1232
1233           sw_ifs++;
1234         }
1235     }
1236 }
1237
1238 static int
1239 api_bridge_domain_dump (vat_main_t *vam)
1240 {
1241   unformat_input_t *i = vam->input;
1242   vl_api_bridge_domain_dump_t *mp;
1243   vl_api_control_ping_t *mp_ping;
1244   u32 bd_id = ~0;
1245   int ret;
1246
1247   /* Parse args required to build the message */
1248   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1249     {
1250       if (unformat (i, "bd_id %d", &bd_id))
1251         ;
1252       else
1253         break;
1254     }
1255
1256   M (BRIDGE_DOMAIN_DUMP, mp);
1257   mp->bd_id = ntohl (bd_id);
1258   S (mp);
1259
1260   /* Use a control ping for synchronization */
1261   PING (&l2_test_main, mp_ping);
1262   S (mp_ping);
1263
1264   W (ret);
1265   return ret;
1266 }
1267
1268 static int
1269 api_bridge_domain_set_default_learn_limit (vat_main_t *vam)
1270 {
1271   return -1;
1272 }
1273
1274 static int
1275 api_bd_ip_mac_flush (vat_main_t *vam)
1276 {
1277   unformat_input_t *i = vam->input;
1278   vl_api_bd_ip_mac_flush_t *mp;
1279   u32 bd_id;
1280   u8 bd_id_set = 0;
1281   int ret;
1282
1283   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1284     {
1285       if (unformat (i, "bd_id %d", &bd_id))
1286         {
1287           bd_id_set++;
1288         }
1289       else
1290         break;
1291     }
1292
1293   if (bd_id_set == 0)
1294     {
1295       errmsg ("missing bridge domain");
1296       return -99;
1297     }
1298
1299   M (BD_IP_MAC_FLUSH, mp);
1300
1301   mp->bd_id = ntohl (bd_id);
1302
1303   S (mp);
1304   W (ret);
1305   return ret;
1306 }
1307
1308 static int
1309 api_bd_ip_mac_dump (vat_main_t *vam)
1310 {
1311   unformat_input_t *i = vam->input;
1312   vl_api_bd_ip_mac_dump_t *mp;
1313   vl_api_control_ping_t *mp_ping;
1314   int ret;
1315   u32 bd_id;
1316   u8 bd_id_set = 0;
1317
1318   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1319     {
1320       if (unformat (i, "bd_id %d", &bd_id))
1321         {
1322           bd_id_set++;
1323         }
1324       else
1325         break;
1326     }
1327
1328   fformat (vam->ofp, "\n%-5s %-7s %-20s %-30s", "bd_id", "is_ipv6",
1329            "mac_address", "ip_address");
1330
1331   /* Dump Bridge Domain Ip to Mac entries */
1332   M (BD_IP_MAC_DUMP, mp);
1333
1334   if (bd_id_set)
1335     mp->bd_id = htonl (bd_id);
1336   else
1337     mp->bd_id = ~0;
1338
1339   S (mp);
1340
1341   /* Use a control ping for synchronization */
1342   PING (&l2_test_main, mp_ping);
1343   S (mp_ping);
1344
1345   W (ret);
1346   return ret;
1347 }
1348
1349 static int
1350 api_bvi_create (vat_main_t *vam)
1351 {
1352   return -1;
1353 }
1354
1355 static int
1356 api_bvi_delete (vat_main_t *vam)
1357 {
1358   return -1;
1359 }
1360
1361 static int
1362 api_bridge_flags (vat_main_t *vam)
1363 {
1364   unformat_input_t *i = vam->input;
1365   vl_api_bridge_flags_t *mp;
1366   u32 bd_id;
1367   u8 bd_id_set = 0;
1368   u8 is_set = 1;
1369   bd_flags_t flags = 0;
1370   int ret;
1371
1372   /* Parse args required to build the message */
1373   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1374     {
1375       if (unformat (i, "bd_id %d", &bd_id))
1376         bd_id_set = 1;
1377       else if (unformat (i, "learn"))
1378         flags |= BRIDGE_API_FLAG_LEARN;
1379       else if (unformat (i, "forward"))
1380         flags |= BRIDGE_API_FLAG_FWD;
1381       else if (unformat (i, "flood"))
1382         flags |= BRIDGE_API_FLAG_FLOOD;
1383       else if (unformat (i, "uu-flood"))
1384         flags |= BRIDGE_API_FLAG_UU_FLOOD;
1385       else if (unformat (i, "arp-term"))
1386         flags |= BRIDGE_API_FLAG_ARP_TERM;
1387       else if (unformat (i, "off"))
1388         is_set = 0;
1389       else if (unformat (i, "disable"))
1390         is_set = 0;
1391       else
1392         break;
1393     }
1394
1395   if (bd_id_set == 0)
1396     {
1397       errmsg ("missing bridge domain");
1398       return -99;
1399     }
1400
1401   M (BRIDGE_FLAGS, mp);
1402
1403   mp->bd_id = ntohl (bd_id);
1404   mp->flags = ntohl (flags);
1405   mp->is_set = is_set;
1406
1407   S (mp);
1408   W (ret);
1409   return ret;
1410 }
1411
1412 #include <vnet/l2/l2.api_test.c>
1413
1414 /*
1415  * Local Variables:
1416  * eval: (c-set-style "gnu")
1417  * End:
1418  */