summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/dslite_cli.c
blob: 515929b21353beb7dc3798a3b590da2fe7aefc78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
6
# Marvel device plugin for VPP    {#marvel_plugin_doc}

##Overview
This plugins provides native device support for Marvell PP2 network device, by use of Marvel Usermode SDK ([MUSDK][1]).
Code is developed and tested on [MACCHIATObin][2] board.

##Prerequisites
Plugins depends on installed MUSDK and Marvell provided linux [kernel][3] with MUSDK provided kernel patches (see `patches/linux` in musdk repo and relevant documentation.
Kernel version used: **4.14.22 armada-18.09.3**
MUSDK version used: **armada-18.09.3**
Following kernel modules from MUSDK must be loaded for plugin to work:
* `musdk_cma.ko`
* `mv_pp_uio.ko`

##Musdk 18.09.3 compilation steps

```
./bootstrap
./configure --prefix=/opt/vpp/external/aarch64/ CFLAGS="-Wno-error=unused-result -g -fPIC" --enable-shared=no
sed -i -e  's/marvell,mv-pp-uio/generic-uio/' modules/pp2/mv_pp_uio.c
sed -i -e  's/O_CREAT/O_CREAT, S_IRUSR | S_IWUSR/' src/lib/file_utils.c
make
sudo make install
```

## Usage
### Interface Cration
Interfaces are dynamically created with following CLI:
```
create interface marvell pp2 name eth0
set interface state mv-ppio-0/0 up
```

Where `eth0` is linux interface name  and `mv-ppio-X/Y` is VPP interface name where X is PP2 device ID and Y is PPIO ID
Interface needs to be assigned to MUSDK in FDT configuration and linux interface state must be up.

### Interface Deletion
Interface can be deleted with following CLI:
```
delete interface marvell pp2 <interface name>
```


### Interface Statistics
Interface statistics can be displayed with `sh hardware-interface mv-ppio0/0`
command.

### Interaction with DPDK plugin
This plugin doesn't have any dependency on DPDK or DPDK plugin but it can
work with DPDK plugin enabled or disabled. It is observed that performace is
better around 30% when DPDK plugin is disabled, as DPDK plugin registers 
own buffer manager, which needs to deal with additional metadata in each packet.

DPKD plugin can be disabled by adding following config to the startup.conf.

```
plugins {
  dpdk_plugin.so { disable }
}
```


[
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <nat/dslite.h>

static clib_error_t *
dslite_add_del_pool_addr_command_fn (vlib_main_t * vm,
				     unformat_input_t * input,
				     vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;
  unformat_input_t _line_input, *line_input = &_line_input;
  ip4_address_t start_addr, end_addr, this_addr;
  u32 start_host_order, end_host_order;
  int i, count, rv;
  u8 is_add = 1;
  clib_error_t *error = 0;

  /* Get a line of input. */
  if (!unformat_user (input, unformat_line_input, line_input))
    return 0;

  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (line_input, "%U - %U",
		    unformat_ip4_address, &start_addr,
		    unformat_ip4_address, &end_addr))
	;
      else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
	end_addr = start_addr;
      else if (unformat (line_input, "del"))
	is_add = 0;
      else
	{
	  error = clib_error_return (0, "unknown input '%U'",
				     format_unformat_error, line_input);
	  goto done;
	}
    }

  start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
  end_host_order = clib_host_to_net_u32 (end_addr.as_u32);

  if (end_host_order < start_host_order)
    {
      error = clib_error_return (0, "end address less than start address");
      goto done;
    }

  count = (end_host_order - start_host_order) + 1;
  this_addr = start_addr;

  for (i = 0; i < count; i++)
    {
      rv = dslite_add_del_pool_addr (dm, &this_addr, is_add);

      switch (rv)
	{
	case VNET_API_ERROR_NO_SUCH_ENTRY:
	  error =
	    clib_error_return (0, "DS-Lite pool address %U not exist.",
			       format_ip4_address, &this_addr);
	  goto done;
	case VNET_API_ERROR_VALUE_EXIST:
	  error =
	    clib_error_return (0, "DS-Lite pool address %U exist.",
			       format_ip4_address, &this_addr);
	  goto done;
	default:
	  break;

	}
      increment_v4_address (&this_addr);
    }

done:
  unformat_free (line_input);

  return error;
}

static clib_error_t *
dslite_show_pool_command_fn (vlib_main_t * vm,
			     unformat_input_t * input,
			     vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;
  snat_address_t *ap;

  vlib_cli_output (vm, "DS-Lite pool:");

  /* *INDENT-OFF* */
  vec_foreach (ap, dm->addr_pool)
    {
      vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
    }
  /* *INDENT-ON* */
  return 0;
}

static clib_error_t *
dslite_set_aftr_tunnel_addr_command_fn (vlib_main_t * vm,
					unformat_input_t * input,
					vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;
  unformat_input_t _line_input, *line_input = &_line_input;
  ip6_address_t ip6_addr;
  int rv;
  clib_error_t *error = 0;

  /* Get a line of input. */
  if (!unformat_user (input, unformat_line_input, line_input))
    return 0;

  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (line_input, "%U", unformat_ip6_address, &ip6_addr))
	;
      else
	{
	  error = clib_error_return (0, "unknown input '%U'",
				     format_unformat_error, line_input);
	  goto done;
	}
    }

  rv = dslite_set_aftr_ip6_addr (dm, &ip6_addr);

  if (rv)
    error =
      clib_error_return (0,
			 "Set DS-Lite AFTR tunnel endpoint address failed.");

done:
  unformat_free (line_input);

  return error;
}

static clib_error_t *
dslite_show_aftr_ip6_addr_command_fn (vlib_main_t * vm,
				      unformat_input_t * input,
				      vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;

  vlib_cli_output (vm, "%U", format_ip6_address, &dm->aftr_ip6_addr);
  return 0;
}

static clib_error_t *
dslite_set_b4_tunnel_addr_command_fn (vlib_main_t * vm,
				      unformat_input_t * input,
				      vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;
  unformat_input_t _line_input, *line_input = &_line_input;
  ip6_address_t ip6_addr;
  int rv;
  clib_error_t *error = 0;

  /* Get a line of input. */
  if (!unformat_user (input, unformat_line_input, line_input))
    return 0;

  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (line_input, "%U", unformat_ip6_address, &ip6_addr))
	;
      else
	{
	  error = clib_error_return (0, "unknown input '%U'",
				     format_unformat_error, line_input);
	  goto done;
	}
    }

  rv = dslite_set_b4_ip6_addr (dm, &ip6_addr);

  if (rv)
    error =
      clib_error_return (0, "Set DS-Lite B4 tunnel endpoint address failed.");

done:
  unformat_free (line_input);

  return error;
}

static clib_error_t *
dslite_show_b4_ip6_addr_command_fn (vlib_main_t * vm,
				    unformat_input_t * input,
				    vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;

  vlib_cli_output (vm, "%U", format_ip6_address, &dm->b4_ip6_addr);
  return 0;
}

static u8 *
format_dslite_session (u8 * s, va_list * args)
{
  dslite_session_t *session = va_arg (*args, dslite_session_t *);
  u32 indent = format_get_indent (s);

  s = format (s, "%Uin %U:%u out %U:%u protocol %U\n",
	      format_white_space, indent + 2,
	      format_ip4_address, &session->in2out.addr,
	      clib_net_to_host_u16 (session->in2out.port),
	      format_ip4_address, &session->out2in.addr,
	      clib_net_to_host_u16 (session->out2in.port),
	      format_snat_protocol, session->in2out.proto);
  s = format (s, "%Utotal pkts %d, total bytes %lld\n",
	      format_white_space, indent + 4,
	      session->total_pkts, session->total_bytes);
  return s;
}

static u8 *
format_dslite_b4 (u8 * s, va_list * args)
{
  dslite_per_thread_data_t *td = va_arg (*args, dslite_per_thread_data_t *);
  dslite_b4_t *b4 = va_arg (*args, dslite_b4_t *);
  dlist_elt_t *head, *elt;
  u32 elt_index, head_index;
  u32 session_index;
  dslite_session_t *session;

  s =
    format (s, "B4 %U %d sessions\n", format_ip6_address, &b4->addr,
	    b4->nsessions);

  if (b4->nsessions == 0)
    return s;

  head_index = b4->sessions_per_b4_list_head_index;
  head = pool_elt_at_index (td->list_pool, head_index);
  elt_index = head->next;
  elt = pool_elt_at_index (td->list_pool, elt_index);
  session_index = elt->value;
  while (session_index != ~0)
    {
      session = pool_elt_at_index (td->sessions, session_index);
      s = format (s, "%U", format_dslite_session, session);
      elt_index = elt->next;
      elt = pool_elt_at_index (td->list_pool, elt_index);
      session_index = elt->value;
    }

  return s;
}

static clib_error_t *
dslite_show_sessions_command_fn (vlib_main_t * vm,
				 unformat_input_t * input,
				 vlib_cli_command_t * cmd)
{
  dslite_main_t *dm = &dslite_main;
  dslite_per_thread_data_t *td;
  dslite_b4_t *b4;

  /* *INDENT-OFF* */
  vec_foreach (td, dm->per_thread_data)
    {
      pool_foreach (b4, td->b4s,
      ({
        vlib_cli_output (vm, "%U", format_dslite_b4, td, b4);
      }));
    }
  /* *INDENT-ON* */

  return 0;
}

/* *INDENT-OFF* */

/*?
 * @cliexpar
 * @cliexstart{dslite add pool address}
 * Add/delete DS-Lite pool address for AFTR element.
 * To add DS-Lite pool address use:
 *  vpp# dslite add pool address 10.1.1.3
 * To add DS-Lite pool address range use:
 *  vpp# dslite add pool address 10.1.1.5 - 10.1.1.7
 * @cliexend
?*/
VLIB_CLI_COMMAND (dslite_add_pool_address_command, static) = {
  .path = "dslite add pool address",
  .short_help = "dslite add pool address <ip4-range-start> [- <ip4-range-end>] "
                " [del]",
  .function = dslite_add_del_pool_addr_command_fn,
};

/*?
 * @cliexpar
 * @cliexstart{show dslite pool}
 * Show DS-lite pool addresses.
 * vpp# show dslite pool
 * DS-Lite pool:
 * 10.0.0.3
 * 10.0.0.5
 * 10.0.0.6
 * 10.0.0.7
 * @cliexend
?*/
VLIB_CLI_COMMAND (show_dslite_pool_command, static) = {
  .path = "show dslite pool",
  .short_help = "show dslite pool",
  .function = dslite_show_pool_command_fn,
};

/*?
 * @cliexpar
 * @cliexstart{dslite set aftr-tunnel-endpoint-address}
 * Set IPv6 tunnel endpoint address of the AFTR element.
 * To set AFTR tunnel endpoint address use:
 * vpp# dslite set aftr-tunnel-endpoint-address 2001:db8:85a3::8a2e:370:1
 * @cliexend
?*/
VLIB_CLI_COMMAND (dslite_set_aftr_tunnel_addr, static) = {
  .path = "dslite set aftr-tunnel-endpoint-address",
  .short_help = "dslite set aftr-tunnel-endpoint-address <ip6>",
  .function = dslite_set_aftr_tunnel_addr_command_fn,
};

/*?
 * @cliexpar
 * @cliexstart{show dslite aftr-tunnel-endpoint-address}
 * Show IPv6 tunnel endpoint address of the AFTR element.
 * vpp# show dslite aftr-tunnel-endpoint-address
 * 2001:db8:85a3::8a2e:370:1
 * @cliexend
?*/
VLIB_CLI_COMMAND (dslite_show_aftr_ip6_addr, static) = {
  .path = "show dslite aftr-tunnel-endpoint-address",
  .short_help = "show dslite aftr-tunnel-endpoint-address",
  .function = dslite_show_aftr_ip6_addr_command_fn,
};

/*?
 * @cliexpar
 * @cliexstart{dslite set b4-tunnel-endpoint-address}
 * Set IPv6 tunnel endpoint address of the B4 element.
 * To set B4 tunnel endpoint address use:
 * vpp# dslite set b4-tunnel-endpoint-address 2001:db8:62aa::375e:f4c1:1
 * @cliexend
?*/
VLIB_CLI_COMMAND (dslite_set_b4_tunnel_addr, static) = {
  .path = "dslite set b4-tunnel-endpoint-address",
  .short_help = "dslite set b4-tunnel-endpoint-address <ip6>",
  .function = dslite_set_b4_tunnel_addr_command_fn,
};

/*?
 * @cliexpar
 * @cliexstart{show dslite b4-tunnel-endpoint-address}
 * Show IPv6 tunnel endpoint address of the B4 element.
 * vpp# show dslite b4-tunnel-endpoint-address
 * 2001:db8:62aa::375e:f4c1:1
 * @cliexend
?*/
VLIB_CLI_COMMAND (dslite_show_b4_ip6_addr, static) = {
  .path = "show dslite b4-tunnel-endpoint-address",
  .short_help = "show dslite b4-tunnel-endpoint-address",
  .function = dslite_show_b4_ip6_addr_command_fn,
};

/*?
 * @cliexpar
 * @cliexstart{show dslite sessions}
 * Show DS-Lite sessions.
 * vpp# show dslite sessions
 * B4 fd01:2::2 1 sessions
 *   in 192.168.1.1:20000 out 10.0.0.3:16253 protocol udp
 *     total pkts 2, total bytes 136
 * B4 fd01:2::3 2 sessions
 *   in 192.168.1.1:20001 out 10.0.0.3:18995 protocol tcp
 *     total pkts 2, total bytes 160
 *   in 192.168.1.1:4000 out 10.0.0.3:53893 protocol icmp
 *     total pkts 2, total bytes 136
 * @cliexend
?*/
VLIB_CLI_COMMAND (dslite_show_sessions, static) = {
  .path = "show dslite sessions",
  .short_help = "show dslite sessions",
  .function = dslite_show_sessions_command_fn,
};

/* *INDENT-ON* */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */