X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=vnet%2Fvnet%2Fl2%2Fl2_output.c;h=acca349475c998dfe801e18eacd4a937c8294b31;hb=1f0da170e818a6991d841df47de0885da720b0c3;hp=31287645b14e3ace13effdcf8ca000df8523b9aa;hpb=1549b61e76a87e88b4c35c56e63dcbd61e00943b;p=vpp.git diff --git a/vnet/vnet/l2/l2_output.c b/vnet/vnet/l2/l2_output.c index 31287645b14..acca349475c 100644 --- a/vnet/vnet/l2/l2_output.c +++ b/vnet/vnet/l2/l2_output.c @@ -62,31 +62,12 @@ static u8 * format_l2output_trace (u8 * s, va_list * args) } -#define foreach_l2output_error \ -_(L2OUTPUT, "L2 output packets") \ -_(EFP_DROP, "L2 EFP filter pre-rewrite drops") \ -_(VTR_DROP, "L2 output tag rewrite drops") \ -_(SHG_DROP, "L2 split horizon drops") \ -_(DROP, "L2 output drops") - -typedef enum { -#define _(sym,str) L2OUTPUT_ERROR_##sym, - foreach_l2output_error -#undef _ - L2OUTPUT_N_ERROR, -} l2output_error_t; - static char * l2output_error_strings[] = { #define _(sym,string) string, foreach_l2output_error #undef _ }; -typedef enum { - L2OUTPUT_NEXT_DROP, - L2OUTPUT_N_NEXT, -} l2output_next_t; - // Return 0 if split horizon check passes, otherwise return non-zero // Packets should not be transmitted out an interface with the same // split-horizon group as the input interface, except if the shg is 0 @@ -102,6 +83,8 @@ split_horizon_violation (u8 shg1, u8 shg2) } +static vlib_node_registration_t l2output_node; + static uword l2output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -190,16 +173,16 @@ l2output_node_fn (vlib_main_t * vm, l2output_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); t->sw_if_index = sw_if_index0; - memcpy(t->src, h0->src_address, 6); - memcpy(t->dst, h0->dst_address, 6); + clib_memcpy(t->src, h0->src_address, 6); + clib_memcpy(t->dst, h0->dst_address, 6); } if (b1->flags & VLIB_BUFFER_IS_TRACED) { l2output_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t)); t->sw_if_index = sw_if_index1; - memcpy(t->src, h1->src_address, 6); - memcpy(t->dst, h1->dst_address, 6); + clib_memcpy(t->src, h1->src_address, 6); + clib_memcpy(t->dst, h1->dst_address, 6); } } @@ -327,8 +310,8 @@ l2output_node_fn (vlib_main_t * vm, vlib_add_trace (vm, node, b0, sizeof (*t)); t->sw_if_index = sw_if_index0; h0 = vlib_buffer_get_current (b0); - memcpy(t->src, h0->src_address, 6); - memcpy(t->dst, h0->dst_address, 6); + clib_memcpy(t->src, h0->src_address, 6); + clib_memcpy(t->dst, h0->dst_address, 6); } em->counters[node_counter_base_index + L2OUTPUT_ERROR_L2OUTPUT] += 1; @@ -394,7 +377,7 @@ l2output_node_fn (vlib_main_t * vm, } -VLIB_REGISTER_NODE (l2output_node) = { +VLIB_REGISTER_NODE (l2output_node,static) = { .function = l2output_node_fn, .name = "l2-output", .vector_size = sizeof (u32), @@ -409,9 +392,116 @@ VLIB_REGISTER_NODE (l2output_node) = { /* edit / add dispositions here */ .next_nodes = { [L2OUTPUT_NEXT_DROP] = "error-drop", + [L2OUTPUT_NEXT_DEL_TUNNEL] = "l2-output-del-tunnel", + }, +}; + + +#define foreach_l2output_del_tunnel_error \ +_(DROP, "L2 output to deleted tunnel") + +static char * l2output_del_tunnel_error_strings[] = { +#define _(sym,string) string, + foreach_l2output_del_tunnel_error +#undef _ +}; + +typedef enum { +#define _(sym,str) L2OUTPUT_DEL_TUNNEL_ERROR_##sym, + foreach_l2output_del_tunnel_error +#undef _ + L2OUTPUT_DEL_TUNNEL_N_ERROR, +} l2output_del_tunnel_error_t; + + +// Output node for tunnels which was in L2 BD's but were deleted. +// On deletion of any tunnel which was on a L2 BD, its entry in +// l2_output_main table next_nodes.output_node_index_vec[sw_if_index] +// MUST be set to the value of L2OUTPUT_NEXT_DEL_TUNNEL. Thus, if there +// are stale entries in the L2FIB for this tunnel sw_if_index, l2-output +// will send packets for this sw_if_index to the l2-output-tunnel-del +// node which just setup the proper drop reason before sending packets +// to the error-drop node to drop the packet. Then, stale L2FIB entries +// for delted tunnels won't cause possible packet or memory corrpution. +static vlib_node_registration_t l2output_del_tunnel_node; + +static uword +l2output_del_tunnel_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + l2output_next_t next_index = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; // number of packets to process + + while (n_left_from > 0) + { + u32 n_left_to_next; + + // get space to enqueue frame to graph node "next_index" + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t * b0, * b1; + + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + b0->error = node->errors[L2OUTPUT_DEL_TUNNEL_ERROR_DROP]; + b1->error = node->errors[L2OUTPUT_DEL_TUNNEL_ERROR_DROP]; + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + b0 = vlib_get_buffer (vm, bi0); + b0->error = node->errors[L2OUTPUT_DEL_TUNNEL_ERROR_DROP]; + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (l2output_del_tunnel_node,static) = { + .function = l2output_del_tunnel_node_fn, + .name = "l2-output-del-tunnel", + .vector_size = sizeof (u32), + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2output_del_tunnel_error_strings), + .error_strings = l2output_del_tunnel_error_strings, + + .n_next_nodes = 1, + + /* edit / add dispositions here */ + .next_nodes = { + [0] = "error-drop", }, }; + +VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn) + clib_error_t *l2output_init (vlib_main_t *vm) { l2output_main_t * mp = &l2output_main; @@ -485,17 +575,15 @@ u32 l2output_create_output_node_mapping ( if (cpu_number) { u32 oldflags; - vlib_node_t *error_drop_node; - error_drop_node = vlib_get_node_by_name (vlib_main, (u8 *) "error-drop"); oldflags = __sync_fetch_and_or(&hw0->flags, VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED); if ((oldflags & VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED) ) - return error_drop_node->index; + return L2OUTPUT_NEXT_DROP; output_node_mapping_send_rpc (node_index, sw_if_index); - return error_drop_node->index; + return L2OUTPUT_NEXT_DROP; } #endif