ipsec: add per-SA error counters
[vpp.git] / src / vnet / pg / cli.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * pg_cli.c: packet generator cli
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <sys/stat.h>
41
42 #include <vnet/vnet.h>
43 #include <vnet/pg/pg.h>
44
45 #include <strings.h>
46 #include <vppinfra/pcap.h>
47
48
49 /* Root of all packet generator cli commands. */
50 /* *INDENT-OFF* */
51 VLIB_CLI_COMMAND (vlib_cli_pg_command, static) = {
52   .path = "packet-generator",
53   .short_help = "Packet generator commands",
54 };
55 /* *INDENT-ON* */
56
57 void
58 pg_enable_disable (u32 stream_index, int is_enable)
59 {
60   pg_main_t *pg = &pg_main;
61   pg_stream_t *s;
62
63   if (stream_index == ~0)
64     {
65       /* No stream specified: enable/disable all streams. */
66       /* *INDENT-OFF* */
67         pool_foreach (s, pg->streams)  {
68             pg_stream_enable_disable (pg, s, is_enable);
69         }
70         /* *INDENT-ON* */
71     }
72   else
73     {
74       /* enable/disable specified stream. */
75       s = pool_elt_at_index (pg->streams, stream_index);
76       pg_stream_enable_disable (pg, s, is_enable);
77     }
78 }
79
80 clib_error_t *
81 pg_capture (pg_capture_args_t * a)
82 {
83   pg_main_t *pg = &pg_main;
84   pg_interface_t *pi;
85
86   if (a->is_enabled == 1)
87     {
88       struct stat sb;
89       if (stat (a->pcap_file_name, &sb) != -1)
90         return clib_error_return (0, "pcap file '%s' already exists.",
91                                   a->pcap_file_name);
92     }
93
94   pi = pool_elt_at_index (pg->interfaces, a->dev_instance);
95   vec_free (pi->pcap_file_name);
96   if ((pi->pcap_main.flags & PCAP_MAIN_INIT_DONE))
97     pcap_close (&pi->pcap_main);
98   clib_memset (&pi->pcap_main, 0, sizeof (pi->pcap_main));
99   pi->pcap_main.file_descriptor = -1;
100
101   if (a->is_enabled == 0)
102     return 0;
103
104   pi->pcap_file_name = a->pcap_file_name;
105   pi->pcap_main.file_name = (char *) pi->pcap_file_name;
106   pi->pcap_main.n_packets_to_capture = a->count;
107   pi->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
108
109   return 0;
110 }
111
112 static clib_error_t *
113 enable_disable_stream (vlib_main_t * vm,
114                        unformat_input_t * input, vlib_cli_command_t * cmd)
115 {
116   unformat_input_t _line_input, *line_input = &_line_input;
117   pg_main_t *pg = &pg_main;
118   int is_enable = cmd->function_arg != 0;
119   u32 stream_index = ~0;
120
121   if (!unformat_user (input, unformat_line_input, line_input))
122     goto doit;
123
124   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
125     {
126       if (unformat (line_input, "%U", unformat_hash_vec_string,
127                     pg->stream_index_by_name, &stream_index))
128         ;
129       else
130         return clib_error_create ("unknown input `%U'",
131                                   format_unformat_error, line_input);
132     }
133   unformat_free (line_input);
134
135 doit:
136   pg_enable_disable (stream_index, is_enable);
137
138   return 0;
139 }
140
141 /* *INDENT-OFF* */
142 VLIB_CLI_COMMAND (enable_streams_cli, static) = {
143   .path = "packet-generator enable-stream",
144   .short_help = "Enable packet generator streams",
145   .function = enable_disable_stream,
146   .function_arg = 1,            /* is_enable */
147 };
148 /* *INDENT-ON* */
149
150 /* *INDENT-OFF* */
151 VLIB_CLI_COMMAND (disable_streams_cli, static) = {
152   .path = "packet-generator disable-stream",
153   .short_help = "Disable packet generator streams",
154   .function = enable_disable_stream,
155   .function_arg = 0,            /* is_enable */
156 };
157 /* *INDENT-ON* */
158
159 static u8 *
160 format_pg_edit_group (u8 * s, va_list * va)
161 {
162   pg_edit_group_t *g = va_arg (*va, pg_edit_group_t *);
163
164   s =
165     format (s, "hdr-size %d, offset %d, ", g->n_packet_bytes,
166             g->start_byte_offset);
167   if (g->edit_function)
168     {
169       u8 *function_name;
170       u8 *junk_after_name;
171       function_name = format (0, "%U%c", format_clib_elf_symbol_with_address,
172                               g->edit_function, 0);
173       junk_after_name = function_name;
174       while (*junk_after_name && *junk_after_name != ' ')
175         junk_after_name++;
176       *junk_after_name = 0;
177       s = format (s, "edit-function %s, ", function_name);
178       vec_free (function_name);
179     }
180
181   return s;
182 }
183
184 static u8 *
185 format_pg_stream (u8 * s, va_list * va)
186 {
187   pg_stream_t *t = va_arg (*va, pg_stream_t *);
188   int verbose = va_arg (*va, int);
189
190   if (!t)
191     return format (s, "%-16s%=12s%=16s%s",
192                    "Name", "Enabled", "Count", "Parameters");
193
194   s = format (s, "%-16v%=12s%=16Ld",
195               t->name,
196               pg_stream_is_enabled (t) ? "Yes" : "No",
197               t->n_packets_generated);
198
199   int indent = format_get_indent (s);
200
201   s = format (s, "limit %Ld, ", t->n_packets_limit);
202   s = format (s, "rate %.2e pps, ", t->rate_packets_per_second);
203   s = format (s, "size %d%c%d, ",
204               t->min_packet_bytes,
205               t->packet_size_edit_type == PG_EDIT_RANDOM ? '+' : '-',
206               t->max_packet_bytes);
207   s = format (s, "buffer-size %d, ", t->buffer_bytes);
208   s = format (s, "worker %d, ", t->worker_index);
209
210   if (verbose)
211     {
212       pg_edit_group_t *g;
213   /* *INDENT-OFF* */
214   vec_foreach (g, t->edit_groups)
215     {
216       s = format (s, "\n%U%U", format_white_space, indent, format_pg_edit_group, g);
217     }
218   /* *INDENT-ON* */
219     }
220
221   return s;
222 }
223
224 static clib_error_t *
225 show_streams (vlib_main_t * vm,
226               unformat_input_t * input, vlib_cli_command_t * cmd)
227 {
228   pg_main_t *pg = &pg_main;
229   pg_stream_t *s;
230   int verbose = 0;
231
232   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
233     {
234       if (unformat (input, "verbose"))
235         verbose = 1;
236       else
237         break;
238     }
239
240   if (pool_elts (pg->streams) == 0)
241     {
242       vlib_cli_output (vm, "no streams currently defined");
243       goto done;
244     }
245
246   vlib_cli_output (vm, "%U", format_pg_stream, 0, 0);
247   /* *INDENT-OFF* */
248   pool_foreach (s, pg->streams)  {
249       vlib_cli_output (vm, "%U", format_pg_stream, s, verbose);
250     }
251   /* *INDENT-ON* */
252
253 done:
254   return 0;
255 }
256
257 /* *INDENT-OFF* */
258 VLIB_CLI_COMMAND (show_streams_cli, static) = {
259   .path = "show packet-generator ",
260   .short_help = "show packet-generator [verbose]",
261   .function = show_streams,
262 };
263 /* *INDENT-ON* */
264
265 static clib_error_t *
266 pg_pcap_read (pg_stream_t * s, char *file_name)
267 {
268 #ifndef CLIB_UNIX
269   return clib_error_return (0, "no pcap support");
270 #else
271   pcap_main_t pm;
272   clib_error_t *error;
273   clib_memset (&pm, 0, sizeof (pm));
274   pm.file_name = file_name;
275   error = pcap_read (&pm);
276   s->replay_packet_templates = pm.packets_read;
277   s->replay_packet_timestamps = pm.timestamps;
278   s->min_packet_bytes = pm.min_packet_bytes;
279   s->max_packet_bytes = pm.max_packet_bytes;
280   s->buffer_bytes = pm.max_packet_bytes;
281
282   if (s->n_packets_limit == 0)
283     s->n_packets_limit = vec_len (pm.packets_read);
284
285   return error;
286 #endif /* CLIB_UNIX */
287 }
288
289 static uword
290 unformat_pg_stream_parameter (unformat_input_t * input, va_list * args)
291 {
292   pg_stream_t *s = va_arg (*args, pg_stream_t *);
293   f64 x;
294
295   if (unformat (input, "limit %f", &x))
296     s->n_packets_limit = x;
297
298   else if (unformat (input, "rate %f", &x))
299     s->rate_packets_per_second = x;
300
301   else if (unformat (input, "size %d-%d", &s->min_packet_bytes,
302                      &s->max_packet_bytes))
303     s->packet_size_edit_type = PG_EDIT_INCREMENT;
304
305   else if (unformat (input, "size %d+%d", &s->min_packet_bytes,
306                      &s->max_packet_bytes))
307     s->packet_size_edit_type = PG_EDIT_RANDOM;
308
309   else if (unformat (input, "buffer-size %d", &s->buffer_bytes))
310     ;
311
312   else
313     return 0;
314
315   return 1;
316 }
317
318 static clib_error_t *
319 validate_stream (pg_stream_t * s)
320 {
321   if (s->max_packet_bytes < s->min_packet_bytes)
322     return clib_error_create ("max-size < min-size");
323
324   u32 hdr_size = pg_edit_group_n_bytes (s, 0);
325   if (s->min_packet_bytes < hdr_size)
326     return clib_error_create ("min-size < total header size %d", hdr_size);
327   if (s->buffer_bytes == 0)
328     return clib_error_create ("buffer-size must be positive");
329
330   if (s->rate_packets_per_second < 0)
331     return clib_error_create ("negative rate");
332
333   return 0;
334 }
335
336 const char *
337 pg_interface_get_input_node (pg_interface_t *pi)
338 {
339   switch (pi->mode)
340     {
341     case PG_MODE_ETHERNET:
342       return ("ethernet-input");
343     case PG_MODE_IP4:
344       return ("ip4-input");
345     case PG_MODE_IP6:
346       return ("ip6-input");
347     }
348
349   ASSERT (0);
350   return ("ethernet-input");
351 }
352
353 static clib_error_t *
354 new_stream (vlib_main_t * vm,
355             unformat_input_t * input, vlib_cli_command_t * cmd)
356 {
357   clib_error_t *error = 0;
358   u8 *tmp = 0;
359   u32 maxframe, hw_if_index;
360   unformat_input_t sub_input = { 0 };
361   int sub_input_given = 0;
362   vnet_main_t *vnm = vnet_get_main ();
363   pg_main_t *pg = &pg_main;
364   pg_stream_t s = { 0 };
365   char *pcap_file_name;
366
367   s.sw_if_index[VLIB_RX] = s.sw_if_index[VLIB_TX] = ~0;
368   s.node_index = ~0;
369   s.max_packet_bytes = s.min_packet_bytes = 64;
370   s.buffer_bytes = vlib_buffer_get_default_data_size (vm);
371   s.if_id = ~0;
372   s.n_max_frame = VLIB_FRAME_SIZE;
373   pcap_file_name = 0;
374
375   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
376     {
377       if (unformat (input, "name %v", &tmp))
378         {
379           if (s.name)
380             vec_free (s.name);
381           s.name = tmp;
382         }
383
384       else if (unformat (input, "node %U",
385                          unformat_vnet_hw_interface, vnm, &hw_if_index))
386         {
387           vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
388
389           s.node_index = hi->output_node_index;
390           s.sw_if_index[VLIB_TX] = hi->sw_if_index;
391         }
392
393       else if (unformat (input, "source pg%u", &s.if_id))
394         ;
395
396       else if (unformat (input, "buffer-flags %U",
397                          unformat_vnet_buffer_flags, &s.buffer_flags))
398         ;
399       else if (unformat (input, "buffer-offload-flags %U",
400                          unformat_vnet_buffer_offload_flags, &s.buffer_oflags))
401         ;
402       else if (unformat (input, "node %U",
403                          unformat_vlib_node, vm, &s.node_index))
404         ;
405       else if (unformat (input, "maxframe %u", &maxframe))
406         s.n_max_frame = s.n_max_frame < maxframe ? s.n_max_frame : maxframe;
407       else if (unformat (input, "worker %u", &s.worker_index))
408         ;
409
410       else if (unformat (input, "interface %U",
411                          unformat_vnet_sw_interface, vnm,
412                          &s.sw_if_index[VLIB_RX]))
413         ;
414       else if (unformat (input, "tx-interface %U",
415                          unformat_vnet_sw_interface, vnm,
416                          &s.sw_if_index[VLIB_TX]))
417         ;
418
419       else if (unformat (input, "pcap %s", &pcap_file_name))
420         ;
421
422       else if (!sub_input_given
423                && unformat (input, "data %U", unformat_input, &sub_input))
424         sub_input_given++;
425
426       else if (unformat_user (input, unformat_pg_stream_parameter, &s))
427         ;
428
429       else
430         {
431           error = clib_error_create ("unknown input `%U'",
432                                      format_unformat_error, input);
433           goto done;
434         }
435     }
436
437   if (!sub_input_given && !pcap_file_name)
438     {
439       error = clib_error_create ("no packet data given");
440       goto done;
441     }
442
443   if (s.node_index == ~0)
444     {
445       if (pcap_file_name != 0)
446         {
447           vlib_node_t *n;
448
449           if (s.if_id != ~0)
450             n = vlib_get_node_by_name (vm, (u8 *) pg_interface_get_input_node (
451                                              &pg->interfaces[s.if_id]));
452           else
453             n = vlib_get_node_by_name (vm, (u8 *) "ethernet-input");
454           s.node_index = n->index;
455         }
456       else
457         {
458           error = clib_error_create ("output interface or node not given");
459           goto done;
460         }
461     }
462
463   {
464     pg_node_t *n;
465
466     if (s.node_index < vec_len (pg->nodes))
467       n = pg->nodes + s.node_index;
468     else
469       n = 0;
470
471     if (s.worker_index >= vlib_num_workers ())
472       s.worker_index = 0;
473
474     if (pcap_file_name != 0)
475       {
476         error = pg_pcap_read (&s, pcap_file_name);
477         if (error)
478           goto done;
479         vec_free (pcap_file_name);
480       }
481
482     else if (n && n->unformat_edit
483              && unformat_user (&sub_input, n->unformat_edit, &s))
484       ;
485
486     else if (!unformat_user (&sub_input, unformat_pg_payload, &s))
487       {
488         error = clib_error_create
489           ("failed to parse packet data from `%U'",
490            format_unformat_error, &sub_input);
491         goto done;
492       }
493   }
494
495   error = validate_stream (&s);
496   if (error)
497     return error;
498
499   pg_stream_add (pg, &s);
500   return 0;
501
502 done:
503   pg_stream_free (&s);
504   unformat_free (&sub_input);
505   return error;
506 }
507
508 /* *INDENT-OFF* */
509 VLIB_CLI_COMMAND (new_stream_cli, static) = {
510   .path = "packet-generator new",
511   .function = new_stream,
512   .short_help = "Create packet generator stream",
513   .long_help =
514   "Create packet generator stream\n"
515   "\n"
516   "Arguments:\n"
517   "\n"
518   "name STRING          sets stream name\n"
519   "interface STRING     interface for stream output \n"
520   "node NODE-NAME       node for stream output\n"
521   "data STRING          specifies packet data\n"
522   "pcap FILENAME        read packet data from pcap file\n"
523   "rate PPS             rate to transfer packet data\n"
524   "maxframe NPKTS       maximum number of packets per frame\n",
525 };
526 /* *INDENT-ON* */
527
528 static clib_error_t *
529 del_stream (vlib_main_t * vm,
530             unformat_input_t * input, vlib_cli_command_t * cmd)
531 {
532   pg_main_t *pg = &pg_main;
533   u32 i;
534
535   if (!unformat (input, "%U",
536                  &unformat_hash_vec_string, pg->stream_index_by_name, &i))
537     return clib_error_create ("expected stream name `%U'",
538                               format_unformat_error, input);
539
540   pg_stream_del (pg, i);
541   return 0;
542 }
543
544 /* *INDENT-OFF* */
545 VLIB_CLI_COMMAND (del_stream_cli, static) = {
546   .path = "packet-generator delete",
547   .function = del_stream,
548   .short_help = "Delete stream with given name",
549 };
550 /* *INDENT-ON* */
551
552 static clib_error_t *
553 change_stream_parameters (vlib_main_t * vm,
554                           unformat_input_t * input, vlib_cli_command_t * cmd)
555 {
556   pg_main_t *pg = &pg_main;
557   pg_stream_t *s, s_new;
558   u32 stream_index = ~0;
559   clib_error_t *error;
560
561   if (unformat (input, "%U", unformat_hash_vec_string,
562                 pg->stream_index_by_name, &stream_index))
563     ;
564   else
565     return clib_error_create ("expecting stream name; got `%U'",
566                               format_unformat_error, input);
567
568   s = pool_elt_at_index (pg->streams, stream_index);
569   s_new = s[0];
570
571   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
572     {
573       if (unformat_user (input, unformat_pg_stream_parameter, &s_new))
574         ;
575
576       else
577         return clib_error_create ("unknown input `%U'",
578                                   format_unformat_error, input);
579     }
580
581   error = validate_stream (&s_new);
582   if (!error)
583     {
584       s[0] = s_new;
585       pg_stream_change (pg, s);
586     }
587
588   return error;
589 }
590
591 /* *INDENT-OFF* */
592 VLIB_CLI_COMMAND (change_stream_parameters_cli, static) = {
593   .path = "packet-generator configure",
594   .short_help = "Change packet generator stream parameters",
595   .function = change_stream_parameters,
596 };
597 /* *INDENT-ON* */
598
599 static clib_error_t *
600 pg_capture_cmd_fn (vlib_main_t * vm,
601                    unformat_input_t * input, vlib_cli_command_t * cmd)
602 {
603   clib_error_t *error = 0;
604   vnet_main_t *vnm = vnet_get_main ();
605   unformat_input_t _line_input, *line_input = &_line_input;
606   vnet_hw_interface_t *hi = 0;
607   u8 *pcap_file_name = 0;
608   u32 hw_if_index;
609   u32 is_disable = 0;
610   u32 count = ~0;
611
612   if (!unformat_user (input, unformat_line_input, line_input))
613     return 0;
614
615   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
616     {
617       if (unformat (line_input, "%U",
618                     unformat_vnet_hw_interface, vnm, &hw_if_index))
619         {
620           hi = vnet_get_hw_interface (vnm, hw_if_index);
621         }
622
623       else if (unformat (line_input, "pcap %s", &pcap_file_name))
624         ;
625       else if (unformat (line_input, "count %u", &count))
626         ;
627       else if (unformat (line_input, "disable"))
628         is_disable = 1;
629
630       else
631         {
632           error = clib_error_create ("unknown input `%U'",
633                                      format_unformat_error, line_input);
634           goto done;
635         }
636     }
637
638   if (!hi)
639     {
640       error = clib_error_return (0, "Please specify interface name");
641       goto done;
642     }
643
644   if (hi->dev_class_index != pg_dev_class.index)
645     {
646       error =
647         clib_error_return (0, "Please specify packet-generator interface");
648       goto done;
649     }
650
651   if (!pcap_file_name && is_disable == 0)
652     {
653       error = clib_error_return (0, "Please specify pcap file name");
654       goto done;
655     }
656
657
658   pg_capture_args_t _a, *a = &_a;
659
660   a->hw_if_index = hw_if_index;
661   a->dev_instance = hi->dev_instance;
662   a->is_enabled = !is_disable;
663   a->pcap_file_name = (char *) pcap_file_name;
664   a->count = count;
665
666   error = pg_capture (a);
667
668 done:
669   unformat_free (line_input);
670
671   return error;
672 }
673
674 /* *INDENT-OFF* */
675 VLIB_CLI_COMMAND (pg_capture_cmd, static) = {
676   .path = "packet-generator capture",
677   .short_help = "packet-generator capture <interface name> pcap <filename> [count <n>]",
678   .function = pg_capture_cmd_fn,
679 };
680 /* *INDENT-ON* */
681
682 static clib_error_t *
683 create_pg_if_cmd_fn (vlib_main_t * vm,
684                      unformat_input_t * input, vlib_cli_command_t * cmd)
685 {
686   pg_main_t *pg = &pg_main;
687   unformat_input_t _line_input, *line_input = &_line_input;
688   u32 if_id, gso_enabled = 0, gso_size = 0, coalesce_enabled = 0;
689   clib_error_t *error = NULL;
690   pg_interface_mode_t mode = PG_MODE_ETHERNET;
691
692   if (!unformat_user (input, unformat_line_input, line_input))
693     return 0;
694
695   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
696     {
697       if (unformat (line_input, "interface pg%u", &if_id))
698         ;
699       else if (unformat (line_input, "coalesce-enabled"))
700         coalesce_enabled = 1;
701       else if (unformat (line_input, "gso-enabled"))
702         {
703           gso_enabled = 1;
704           if (unformat (line_input, "gso-size %u", &gso_size))
705             ;
706           else
707             {
708               error = clib_error_create ("gso enabled but gso size missing");
709               goto done;
710             }
711         }
712       else if (unformat (line_input, "mode ip4"))
713         mode = PG_MODE_IP4;
714       else if (unformat (line_input, "mode ip6"))
715         mode = PG_MODE_IP6;
716       else
717         {
718           error = clib_error_create ("unknown input `%U'",
719                                      format_unformat_error, line_input);
720           goto done;
721         }
722     }
723
724   pg_interface_add_or_get (pg, if_id, gso_enabled, gso_size, coalesce_enabled,
725                            mode);
726
727 done:
728   unformat_free (line_input);
729
730   return error;
731 }
732
733 /* *INDENT-OFF* */
734 VLIB_CLI_COMMAND (create_pg_if_cmd, static) = {
735   .path = "create packet-generator",
736   .short_help = "create packet-generator interface <interface name>"
737                 " [gso-enabled gso-size <size> [coalesce-enabled]]"
738                 " [mode <ethernet | ip4 | ip6>]",
739   .function = create_pg_if_cmd_fn,
740 };
741 /* *INDENT-ON* */
742
743 /* Dummy init function so that we can be linked in. */
744 static clib_error_t *
745 pg_cli_init (vlib_main_t * vm)
746 {
747   return 0;
748 }
749
750 VLIB_INIT_FUNCTION (pg_cli_init);
751
752 /*
753  * fd.io coding-style-patch-verification: ON
754  *
755  * Local Variables:
756  * eval: (c-set-style "gnu")
757  * End:
758  */