pg: A Tunnel mode variant of a pg interface
Type: feature
this allows VPP to simulate linux tun devices.
Signed-off-by: Neale Ranns <neale@graphiant.com>
Change-Id: I3adf38b49a254804370f78edd5d275d192fd00a6
diff --git a/src/vnet/pg/cli.c b/src/vnet/pg/cli.c
index 9da0f8d..e57e725 100644
--- a/src/vnet/pg/cli.c
+++ b/src/vnet/pg/cli.c
@@ -333,6 +333,23 @@
return 0;
}
+const char *
+pg_interface_get_input_node (pg_interface_t *pi)
+{
+ switch (pi->mode)
+ {
+ case PG_MODE_ETHERNET:
+ return ("ethernet-input");
+ case PG_MODE_IP4:
+ return ("ip4-input");
+ case PG_MODE_IP6:
+ return ("ip6-input");
+ }
+
+ ASSERT (0);
+ return ("ethernet-input");
+}
+
static clib_error_t *
new_stream (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -351,7 +368,7 @@
s.node_index = ~0;
s.max_packet_bytes = s.min_packet_bytes = 64;
s.buffer_bytes = vlib_buffer_get_default_data_size (vm);
- s.if_id = 0;
+ s.if_id = ~0;
s.n_max_frame = VLIB_FRAME_SIZE;
pcap_file_name = 0;
@@ -427,8 +444,15 @@
{
if (pcap_file_name != 0)
{
- vlib_node_t *n =
- vlib_get_node_by_name (vm, (u8 *) "ethernet-input");
+ vlib_node_t *n;
+
+ ASSERT (s.if_id != ~0);
+
+ if (s.if_id != ~0)
+ n = vlib_get_node_by_name (vm, (u8 *) pg_interface_get_input_node (
+ &pg->interfaces[s.if_id]));
+ else
+ n = vlib_get_node_by_name (vm, (u8 *) "ethernet-input");
s.node_index = n->index;
}
else
@@ -694,8 +718,8 @@
}
}
- pg_interface_add_or_get (pg, if_id, gso_enabled, gso_size,
- coalesce_enabled);
+ pg_interface_add_or_get (pg, if_id, gso_enabled, gso_size, coalesce_enabled,
+ PG_MODE_ETHERNET);
done:
unformat_free (line_input);
diff --git a/src/vnet/pg/pg.api b/src/vnet/pg/pg.api
index 3a44f1d..3630e0c 100644
--- a/src/vnet/pg/pg.api
+++ b/src/vnet/pg/pg.api
@@ -22,6 +22,13 @@
import "vnet/interface_types.api";
+enum pg_interface_mode : u8
+{
+ PG_API_MODE_ETHERNET = 0,
+ PG_API_MODE_IP4,
+ PG_API_MODE_IP6,
+};
+
/** \brief PacketGenerator create interface request
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -37,6 +44,15 @@
bool gso_enabled;
u32 gso_size;
};
+define pg_create_interface_v2
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t interface_id;
+ bool gso_enabled;
+ u32 gso_size;
+ vl_api_pg_interface_mode_t mode;
+};
/** \brief PacketGenerator create interface response
@param context - sender context, to match reply w/ request
@@ -48,6 +64,12 @@
i32 retval;
vl_api_interface_index_t sw_if_index;
};
+define pg_create_interface_v2_reply
+{
+ u32 context;
+ i32 retval;
+ vl_api_interface_index_t sw_if_index;
+};
/** \brief PacketGenerator interface enable/disable packet coalesce
@param client_index - opaque cookie to identify the sender
diff --git a/src/vnet/pg/pg.h b/src/vnet/pg/pg.h
index da5af25..ffa2f8a 100644
--- a/src/vnet/pg/pg.h
+++ b/src/vnet/pg/pg.h
@@ -299,6 +299,13 @@
_vec_len (s->edit_groups) = i;
}
+typedef enum pg_interface_mode_t_
+{
+ PG_MODE_ETHERNET,
+ PG_MODE_IP4,
+ PG_MODE_IP6,
+} pg_interface_mode_t;
+
typedef struct
{
/* TX lock */
@@ -316,6 +323,7 @@
u32 gso_size;
pcap_main_t pcap_main;
char *pcap_file_name;
+ pg_interface_mode_t mode;
mac_address_t *allowed_mcast_macs;
} pg_interface_t;
@@ -373,9 +381,9 @@
u32 tx_node_index);
/* Find/create free packet-generator interface index. */
-u32 pg_interface_add_or_get (pg_main_t * pg, uword stream_index,
- u8 gso_enabled, u32 gso_size,
- u8 coalesce_enabled);
+u32 pg_interface_add_or_get (pg_main_t *pg, uword stream_index, u8 gso_enabled,
+ u32 gso_size, u8 coalesce_enabled,
+ pg_interface_mode_t mode);
always_inline pg_node_t *
pg_get_node (uword node_index)
diff --git a/src/vnet/pg/pg_api.c b/src/vnet/pg/pg_api.c
index 554e8ea..b3eb315 100644
--- a/src/vnet/pg/pg_api.c
+++ b/src/vnet/pg/pg_api.c
@@ -40,12 +40,13 @@
#include <vlibapi/api_helper_macros.h>
-
-#define foreach_pg_api_msg \
-_(PG_CREATE_INTERFACE, pg_create_interface) \
-_(PG_CAPTURE, pg_capture) \
-_(PG_ENABLE_DISABLE, pg_enable_disable) \
-_(PG_INTERFACE_ENABLE_DISABLE_COALESCE, pg_interface_enable_disable_coalesce)
+#define foreach_pg_api_msg \
+ _ (PG_CREATE_INTERFACE, pg_create_interface) \
+ _ (PG_CREATE_INTERFACE_V2, pg_create_interface_v2) \
+ _ (PG_CAPTURE, pg_capture) \
+ _ (PG_ENABLE_DISABLE, pg_enable_disable) \
+ _ (PG_INTERFACE_ENABLE_DISABLE_COALESCE, \
+ pg_interface_enable_disable_coalesce)
static void
vl_api_pg_create_interface_t_handler (vl_api_pg_create_interface_t * mp)
@@ -54,9 +55,9 @@
int rv = 0;
pg_main_t *pg = &pg_main;
- u32 pg_if_id = pg_interface_add_or_get (pg, ntohl (mp->interface_id),
- mp->gso_enabled,
- ntohl (mp->gso_size), 0);
+ u32 pg_if_id =
+ pg_interface_add_or_get (pg, ntohl (mp->interface_id), mp->gso_enabled,
+ ntohl (mp->gso_size), 0, PG_MODE_ETHERNET);
pg_interface_t *pi = pool_elt_at_index (pg->interfaces, pg_if_id);
/* *INDENT-OFF* */
@@ -68,6 +69,22 @@
}
static void
+vl_api_pg_create_interface_v2_t_handler (vl_api_pg_create_interface_v2_t *mp)
+{
+ vl_api_pg_create_interface_v2_reply_t *rmp;
+ int rv = 0;
+
+ pg_main_t *pg = &pg_main;
+ u32 pg_if_id =
+ pg_interface_add_or_get (pg, ntohl (mp->interface_id), mp->gso_enabled,
+ ntohl (mp->gso_size), 0, (u8) mp->mode);
+ pg_interface_t *pi = pool_elt_at_index (pg->interfaces, pg_if_id);
+
+ REPLY_MACRO2 (VL_API_PG_CREATE_INTERFACE_V2_REPLY,
+ ({ rmp->sw_if_index = ntohl (pi->sw_if_index); }));
+}
+
+static void
vl_api_pg_interface_enable_disable_coalesce_t_handler
(vl_api_pg_interface_enable_disable_coalesce_t * mp)
{
diff --git a/src/vnet/pg/stream.c b/src/vnet/pg/stream.c
index 0ce640b..686627b 100644
--- a/src/vnet/pg/stream.c
+++ b/src/vnet/pg/stream.c
@@ -229,9 +229,29 @@
}
}
+u8 *
+format_pg_tun_tx_trace (u8 *s, va_list *args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+
+ s = format (s, "PG: tunnel (no-encap)");
+ return s;
+}
+
+VNET_HW_INTERFACE_CLASS (pg_tun_hw_interface_class) = {
+ .name = "PG-tun",
+ //.format_header = format_gre_header_with_length,
+ //.unformat_header = unformat_gre_header,
+ .build_rewrite = NULL,
+ //.update_adjacency = gre_update_adj,
+ .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
+};
+
u32
-pg_interface_add_or_get (pg_main_t * pg, uword if_id, u8 gso_enabled,
- u32 gso_size, u8 coalesce_enabled)
+pg_interface_add_or_get (pg_main_t *pg, uword if_id, u8 gso_enabled,
+ u32 gso_size, u8 coalesce_enabled,
+ pg_interface_mode_t mode)
{
vnet_main_t *vnm = vnet_get_main ();
vlib_main_t *vm = vlib_get_main ();
@@ -262,8 +282,20 @@
hw_addr[1] = 0xfe;
pi->id = if_id;
- ethernet_register_interface (vnm, pg_dev_class.index, i, hw_addr,
- &pi->hw_if_index, pg_eth_flag_change);
+ pi->mode = mode;
+
+ switch (pi->mode)
+ {
+ case PG_MODE_ETHERNET:
+ ethernet_register_interface (vnm, pg_dev_class.index, i, hw_addr,
+ &pi->hw_if_index, pg_eth_flag_change);
+ break;
+ case PG_MODE_IP4:
+ case PG_MODE_IP6:
+ pi->hw_if_index = vnet_register_interface (
+ vnm, pg_dev_class.index, i, pg_tun_hw_interface_class.index, i);
+ break;
+ }
hi = vnet_get_hw_interface (vnm, pi->hw_if_index);
if (gso_enabled)
{
@@ -510,9 +542,9 @@
}
/* Find an interface to use. */
- s->pg_if_index =
- pg_interface_add_or_get (pg, s->if_id, 0 /* gso_enabled */ ,
- 0 /* gso_size */ , 0 /* coalesce_enabled */ );
+ s->pg_if_index = pg_interface_add_or_get (
+ pg, s->if_id, 0 /* gso_enabled */, 0 /* gso_size */,
+ 0 /* coalesce_enabled */, PG_MODE_ETHERNET);
if (s->sw_if_index[VLIB_RX] == ~0)
{