参照VPP自带的example,写一个自己的graph node。
1. 定义打印trace时使用的参数。
typedef struct {
u32 sw_if_index;
u8 is_fragment;
u8 is_inner;
u8 protocol;
u32 dst_vm;
i32 port;
} abc_icmp_classify_trace_t;
2. 声明registration函数。
vlib_node_registration_t abc_icmp_classify_node;
3. 打印trace函数实现。
static u8 * format_abc_icmp_classify_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 *);
abc_icmp_classify_trace_t * t = va_arg (*args, abc_icmp_classify_trace_t *);
s = format (s, "abc_icmp_classify: sw_if_index %d is_fragment %d has_inner %d protocol %x dst_vm %x port %d",
t->sw_if_index, t->is_fragment, t->is_inner, t->protocol, t->dst_vm, t->port);
return s;
}
4. 定义下一个node。
typedef enum
{
ABC_ICMP_CLASSIFY_ERROR_DROP,
ABC_ICMP_CLASSIFY_NEXT_L4_REASS,
ABC_ICMP_CLASSIFY_NEXT_PING_REPLY,
ABC_ICMP_CLASSIFY_NEXT_L2_LEARN,
ABC_ICMP_CLASSIFY_N_NEXT
} abc_icmp_classify_next_t;
5. 真正实现该node功能的函数。
abc_icmp_classify_fn (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
u32 n_left_from, * from, * to_next;
abc_icmp_classify_next_t next_index;
vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, abc_icmp_classify_node.index);
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
u8 dst_vm = NOT_FOUND;
u8 flag_frag = 0, flag_inner = 0;
i32 port0 = 0;
while (n_left_from > 0)
{
u32 n_left_to_next;
vlib_get_next_frame (vm, node, next_index,
to_next, n_left_to_next);
while (n_left_from > 0 && n_left_to_next > 0)
{
u32 bi0;
vlib_buffer_t * b0;
ethernet_header_t *en0;
ip4_header_t *ip0;
u8 error0 = ABC_L4_ERROR_NONE;
/* speculatively enqueue b0 to the current next frame */
bi0 = from[0];
to_next[0] = bi0;
from += 1;
to_next += 1;
n_left_from -= 1;
n_left_to_next -= 1;
u32 next0 = ABC_ICMP_CLASSIFY_NEXT_L2_LEARN;
b0 = vlib_get_buffer (vm, bi0);
...
if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
abc_icmp_classify_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
t->is_fragment = flag_frag;
t->is_inner = flag_inner;
t->protocol = ip0->protocol;
t->dst_vm = dst_vm;
t->port = port0;
}
next0 = (error0 == ABC_L4_ERROR_NONE) ? next0 : ABC_ICMP_CLASSIFY_ERROR_DROP;
/* verify speculative enqueue, maybe switch current next frame */
b0->error = error_node->errors[error0];
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
return frame->n_vectors;
}
6. register新node。
VLIB_REGISTER_NODE (abc_icmp_classify_node) = {
.function = abc_icmp_classify_fn,
.name = "abc-icmp-classify",
.vector_size = sizeof (u32),
.format_trace = format_abc_icmp_classify_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ABC_L4_N_ERROR,
.error_strings = abc_l4_error_strings,
.n_next_nodes = ABC_ICMP_CLASSIFY_N_NEXT,
.next_nodes = {
[ABC_ICMP_CLASSIFY_NEXT_L4_REASS] = "abc-l4-reass",
[ABC_ICMP_CLASSIFY_NEXT_PING_REPLY] = "abc-ping-reply",
[ABC_ICMP_CLASSIFY_NEXT_L2_LEARN] = "l2-learn",
[ABC_ICMP_CLASSIFY_ERROR_DROP] = "error-drop",
}
};
7. 放到某个feature中
VNET_FEATURE_INIT (abc_icmp_classify, static) = {
.arc_name = "device-input",
.node_name = "abc-icmp-classify",
};