以下是一个带命令行支持的vpp插件示例,该插件使用VLIB库来处理IPv4数据包并输出打印消息:
- 定义插件的输入和输出结构体,同样我们定义了input_structure_t和output_structure_t结构体,用于输入和输出数据:
typedef struct {
u32 data;
} input_structure_t;
typedef struct {
u8 message[256];
} output_structure_t;
- 编写插件代码。在这个例子中,我们编写了ipv4_hello_world.c文件,其中包含了整个插件的实现。具体代码如下:
#include <vnet/plugin/plugin.h>
#include <vnet/ip/ip.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <plugins/ipv4_hello_world/ipv4_hello_world.api_enum.h>
#include <plugins/ipv4_hello_world/ipv4_hello_world.api_types.h>
#define REPLY_MSG_ID_BASE 0x40000000
typedef struct {
u32 data;
} input_structure_t;
typedef struct {
u8 message[256];
} output_structure_t;
typedef struct {
u32 next_index;
} ipv4_hello_world_trace_t;
/* packet trace format function */
static u8 * format_ipv4_hello_world_trace (u8 * s, va_list * args) {
return s;
}
/* trace config structure */
typedef struct {
/* per-packet trace data */
ipv4_hello_world_trace_t *traces;
/* packet buffer flags */
u8 *buffer_flags;
} ipv4_hello_world_trace_config_t;
/* stats */
#define foreach_ipv4_hello_world_error \
_(NONE, "No error") \
_(DROP, "Drop packets")
typedef enum {
#define _(sym,str) IPV4_HELLO_WORLD_ERROR_##sym,
foreach_ipv4_hello_world_error
#undef _
IPV4_HELLO_WORLD_N_ERROR,
} ipv4_hello_world_error_t;
static char * ipv4_hello_world_error_strings[] = {
#define _(sym,string) string,
foreach_ipv4_hello_world_error
#undef _
};
typedef struct {
/* counter for dropped packets */
vlib_simple_counter_main_t drop_counters;
} ipv4_hello_world_main_t;
/* packet processing function */
static uword ipv4_hello_world_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) {
u32 n_left_from, *from, *to_next;
ipv4_hello_world_main_t *hwm = &ipv4_hello_world_main;
vlib_node_t *n = vlib_get_node_by_name (vm, (u8 *) "ipv4-hello-world");
/* get input/output buffer index */
u32 input_buffer_index = vlib_frame_vector_args (frame);
u32 output_buffer_index = vlib_frame_alloc_output_buffer (vm, &to_next, frame, 1);
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
while (n_left_from > 0) {
u32 n_left_to_next = VLIB_FRAME_SIZE - to_next;
while (n_left_from > 0 && n_left_to_next > 0) {
u32 bi0;
vlib_buffer_t *b0;
input_structure_t *input_data;
output_structure_t *output_data;
int next_index = 0;
bi0 = from[0];
from += 1;
n_left_from -= 1;
b0 = vlib_get_buffer (vm, bi0);
/* get input buffer data */
input_data = vlib_buffer_get_current (b0);
/* get output buffer data */
output_data = vlib_buffer_get_current (vm->buffers[output_buffer_index]);
/* copy message to output */
snprintf ((char *)output_data->message, sizeof(output_data->message), "Hello world! Data: %d", input_data->data);
/* set next node index */
next_index = n->next_nodes[0];
/* send packet to next node */
to_next[0] = bi0;
to_next += 1;
n_left_to_next -= 1;
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, output_buffer_index, 0);
}
}
/* send packets to the next node */
vlib_put_next_frame (vm, node, n->index, frame->n_vectors);
return frame->n_vectors;
}
/* CLI command function */
static clib_error_t *
ipv4_hello_world_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
u32 data = 0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
if (unformat (input, "data %u", &data))
;
else
break;
}
/* construct API message */
vl_api_ipv4_hello_world_t *mp;
u8 *name_copy = NULL;
mp = vl_msg_api_alloc (sizeof (*mp));
memset (mp, 0, sizeof (*mp));
mp->_vl_msg_id = ntohs (VL_API_IPV4_HELLO_WORLD);
mp->client_index = vlib_api_get_client_index (vm);
mp->data = htonl(data);
/* send the message */
vl_msg_api_send_shmem (vlib_api_get_main(), (u8 *)&mp);
return 0;
}
/* message handling function */
static void vl_api_ipv4_hello_world_t_handler (vl_api_ipv4_hello_world_t * mp) {
vlib_main_t * vm = vlib_get_main();
ip4_address_t src, dst;
/* get input/output buffer index */
u32 output_buffer_index = vlib_frame_alloc_output_buffer (vm, NULL, NULL, 1);
/* get output buffer data */
output_structure_t *output_data = vlib_buffer_get_current (vm->buffers[output_buffer_index]);
/* copy message to output */
snprintf ((char *)output_data->message, sizeof(output_data->message), "Hello world! Data: %d", ntohl(mp->data));
/* send reply */
vl_api_ipv4_hello_world_reply_t *rmp;
rmp = vl_msg_api_alloc (sizeof (*rmp));
memset (rmp, 0, sizeof (*rmp));
rmp->_vl_msg_id = ntohs (VL_API_IPV4_HELLO_WORLD_REPLY + REPLY_MSG_ID_BASE);
rmp->retval = 0;
rmp->data = mp->data;
vl_msg_api_send_shmem (vlib_api_get_main(), (u8 *)&rmp);
}
/* register nodes and create arcs */
static clib_error_t * ipv4_hello_world_init (vlib_main_t * vm) {
/* declare node functions */
vlib_node_t *node = &ipv4_hello_world_node;
vlib_node_register (vm, node);
/* set node flags */
node->flags |= VLIB_NODE_FLAG_TRACE_SUPPORTED;
node->function = ipv4_hello_world_node_fn;
/* register input/output structs */
vlib_register_input_node (vm, node->index, VLIB_NODE_STATE_DISABLED, 1, sizeof(input_structure_t), NULL);
vlib_register_output_node (vm, node->index, VLIB_NODE_STATE_DISABLED, 1, sizeof(output_structure_t), NULL);
/* register CLI command */
static vlib_cli_command_t command = {
.path = "ipv4-hello-world",
.short_help = "ipv4-hello-world data <data>",
.function = ipv4_hello_world_command_fn,
};
vlib_cli_register (vm, &command);
/* register message handler */
vl_api_ipv4_hello_world_t_handler_add_cleanup (vm, (void *)vl_api_ipv4_hello_world_t_handler, NULL);
return 0;
}
VLIB_INIT_FUNCTION (ipv4_hello_world_init);
- 构建插件。我们可以将上面的代码保存在$VPP_ROOT/plugins/ipv4_hello_world目录下,并使用以下命令来构建插件:
$ cd $VPP_ROOT
$ make build
- 在vpp中测试插件。可以使用以下命令来启用插件并测试它:
$ vppctl
# set interface ip address GigabitEthernet0/8/0 10.0.0.1/24
# create host-interface name test-hif
# set int state test-hif up
# set int l2 bridge test-hif 1 bvi
# set int ip address test-bvi 10.0.1.1/24
# ping 10.0.1.2 verbose
# ipv4-hello-world data 123
在上面的代码中,我们添加了一个名为ipv4-hello-world的新节点,并使用trace add命令跟踪该节点。然后,我们ping测试10.0.1.2,并通过ipv4-hello-world命令发送一条消息到该节点。
调试和优化插件。确保插件可以正常运行,并使用调试工具和技术来优化其性能和可靠性。
发布插件。如果插件被认为是有价值的,则可以将其发布到VPP社区中,并与其他开发者共享。