tracenode: filtering feature
In order to be able to filter on encapsulated packet, a new node has been added to the ip4/6-unicast arcs. Type: feature Change-Id: I1e8ee05bc6d0fce20cadd8319c81bab260c17d21 Signed-off-by: Maxime Peim <mpeim@cisco.com>
This commit is contained in:
committed by
Beno�t Ganne
parent
2ceb818f8e
commit
77812045e7
@@ -826,6 +826,11 @@ I: npt66
|
||||
M: Ole Troan <otroan@employees.org>
|
||||
F: src/plugins/npt66
|
||||
|
||||
Plugin - Trace node
|
||||
I: tracenode
|
||||
M: Maxime Peim <mpeim@cisco.com>
|
||||
F: src/plugins/tracenode
|
||||
|
||||
cJSON
|
||||
I: cjson
|
||||
M: Ole Troan <ot@cisco.com>
|
||||
|
||||
@@ -1149,6 +1149,8 @@ tpv
|
||||
TPv
|
||||
tracedump
|
||||
Tracedump
|
||||
tracenode
|
||||
Tracenode
|
||||
TRex
|
||||
Tsou
|
||||
ttl
|
||||
|
||||
37
src/plugins/tracenode/CMakeLists.txt
Normal file
37
src/plugins/tracenode/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
# Copyright (c) 2023 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.
|
||||
|
||||
add_vpp_plugin(tracenode
|
||||
SOURCES
|
||||
node.c
|
||||
api.c
|
||||
cli.c
|
||||
plugin.c
|
||||
tracenode.c
|
||||
|
||||
MULTIARCH_SOURCES
|
||||
node.c
|
||||
|
||||
API_FILES
|
||||
tracenode.api
|
||||
|
||||
INSTALL_HEADERS
|
||||
tracenode.h
|
||||
|
||||
API_TEST_SOURCES
|
||||
test.c
|
||||
|
||||
COMPONENT
|
||||
vpp-plugin-devtools
|
||||
)
|
||||
8
src/plugins/tracenode/FEATURE.yaml
Normal file
8
src/plugins/tracenode/FEATURE.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Trace node
|
||||
maintainer: Maxime Peim <mpeim@cisco.com>
|
||||
features:
|
||||
- allow trace filtering on encapsulated (inner) packets
|
||||
description: "Allow tracing on IP feature arc. Encapsulated packets can then be traced and filtered."
|
||||
state: experimental
|
||||
properties: [CLI, API]
|
||||
64
src/plugins/tracenode/api.c
Normal file
64
src/plugins/tracenode/api.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <vlib/vlib.h>
|
||||
#include <tracenode/tracenode.h>
|
||||
#include <vlibmemory/api.h>
|
||||
|
||||
/* define message IDs */
|
||||
#include <tracenode/tracenode.api_enum.h>
|
||||
#include <tracenode/tracenode.api_types.h>
|
||||
|
||||
#define REPLY_MSG_ID_BASE (tnm->msg_id_base)
|
||||
#include <vlibapi/api_helper_macros.h>
|
||||
|
||||
static void
|
||||
vl_api_tracenode_enable_disable_t_handler (
|
||||
vl_api_tracenode_enable_disable_t *mp)
|
||||
{
|
||||
tracenode_main_t *tnm = &tracenode_main;
|
||||
vl_api_tracenode_enable_disable_reply_t *rmp;
|
||||
int rv = 0;
|
||||
|
||||
VALIDATE_SW_IF_INDEX (mp);
|
||||
|
||||
rv = tracenode_feature_enable_disable (ntohl (mp->sw_if_index), mp->is_pcap,
|
||||
mp->enable);
|
||||
|
||||
BAD_SW_IF_INDEX_LABEL;
|
||||
|
||||
REPLY_MACRO (VL_API_TRACENODE_ENABLE_DISABLE_REPLY);
|
||||
}
|
||||
|
||||
#include <tracenode/tracenode.api.c>
|
||||
|
||||
clib_error_t *
|
||||
tracenode_plugin_api_hookup (vlib_main_t *vm)
|
||||
{
|
||||
tracenode_main_t *tnm = &tracenode_main;
|
||||
|
||||
/* ask for a correctly-sized block of API message decode slots */
|
||||
tnm->msg_id_base = setup_message_id_table ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
72
src/plugins/tracenode/cli.c
Normal file
72
src/plugins/tracenode/cli.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <vlib/vlib.h>
|
||||
#include <tracenode/tracenode.h>
|
||||
|
||||
static clib_error_t *
|
||||
tracenode_feature_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
unformat_input_t _line_input, *line_input = &_line_input;
|
||||
u32 sw_if_index = ~0;
|
||||
int enable = 1, is_pcap = 0;
|
||||
int rv;
|
||||
|
||||
/* 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, "disable"))
|
||||
enable = 0;
|
||||
else if (unformat (line_input, "pcap"))
|
||||
is_pcap = 1;
|
||||
else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
|
||||
vnet_get_main (), &sw_if_index))
|
||||
{
|
||||
if (sw_if_index == 0)
|
||||
return clib_error_return (0, "Local interface not supported...");
|
||||
}
|
||||
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
return clib_error_return (0, "Software interface required");
|
||||
|
||||
if ((rv = tracenode_feature_enable_disable (sw_if_index, is_pcap, enable)) !=
|
||||
0)
|
||||
return clib_error_return (
|
||||
0, "vnet_enable_disable_tracenode_feature returned %d", rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (tracenode_feature, static) = {
|
||||
.path = "tracenode feature",
|
||||
.short_help = "tracenode feature <intfc> [disable] [pcap]",
|
||||
.function = tracenode_feature_cmd_fn,
|
||||
};
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
145
src/plugins/tracenode/node.c
Normal file
145
src/plugins/tracenode/node.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <vlib/vlib.h>
|
||||
#include <vnet/feature/feature.h>
|
||||
#include <vnet/classify/pcap_classify.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 sw_if_index;
|
||||
} tracenode_trace_t;
|
||||
|
||||
static u8 *
|
||||
format_tracenode_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 *);
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
tracenode_trace_t *t = va_arg (*args, tracenode_trace_t *);
|
||||
|
||||
s = format (s, "Packet traced from interface %U added",
|
||||
format_vnet_sw_if_index_name, vnm, t->sw_if_index);
|
||||
return s;
|
||||
}
|
||||
|
||||
static_always_inline u32
|
||||
tracenode_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
|
||||
vlib_frame_t *frame, int is_pcap)
|
||||
{
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
vnet_pcap_t *pp = &vnm->pcap;
|
||||
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
|
||||
u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
|
||||
u32 *from = vlib_frame_vector_args (frame), *from0 = from;
|
||||
const u32 n_tot = frame->n_vectors;
|
||||
u32 n_left = n_tot;
|
||||
|
||||
vlib_get_buffers (vm, from, b, n_tot);
|
||||
|
||||
while (n_left > 0)
|
||||
{
|
||||
/* TODO: dual/quad loop */
|
||||
|
||||
/* enqueue b0 to the current next frame */
|
||||
vnet_feature_next_u16 (next, b[0]);
|
||||
|
||||
/* buffer already traced */
|
||||
if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
|
||||
goto skip;
|
||||
|
||||
if (is_pcap && vnet_is_packet_pcaped (pp, b[0], ~0))
|
||||
{
|
||||
pcap_add_buffer (&pp->pcap_main, vm, from0[0],
|
||||
pp->max_bytes_per_pkt);
|
||||
}
|
||||
else if (!is_pcap && vlib_trace_buffer (vm, node, next[0], b[0],
|
||||
1 /* follow_chain */))
|
||||
{
|
||||
tracenode_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof *tr);
|
||||
tr->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
|
||||
}
|
||||
|
||||
skip:
|
||||
b++;
|
||||
from0++;
|
||||
next++;
|
||||
n_left--;
|
||||
}
|
||||
|
||||
vlib_buffer_enqueue_to_next (vm, node, from, nexts, n_tot);
|
||||
return n_tot;
|
||||
}
|
||||
|
||||
VLIB_NODE_FN (trace_filtering_node)
|
||||
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
|
||||
{
|
||||
return tracenode_inline (vm, node, frame, 0 /* is_pcap */);
|
||||
}
|
||||
|
||||
VLIB_NODE_FN (pcap_filtering_node)
|
||||
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
|
||||
{
|
||||
return tracenode_inline (vm, node, frame, 1 /* is_pcap */);
|
||||
}
|
||||
|
||||
VLIB_REGISTER_NODE (trace_filtering_node) = {
|
||||
.name = "trace-filtering",
|
||||
.vector_size = sizeof (u32),
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
.format_trace = format_tracenode_trace,
|
||||
};
|
||||
|
||||
VLIB_REGISTER_NODE (pcap_filtering_node) = {
|
||||
.name = "pcap-filtering",
|
||||
.vector_size = sizeof (u32),
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
.format_trace = format_tracenode_trace,
|
||||
};
|
||||
|
||||
VNET_FEATURE_INIT (trace_filtering4, static) = {
|
||||
.arc_name = "ip4-unicast",
|
||||
.node_name = "trace-filtering",
|
||||
.runs_after = VNET_FEATURES ("ip4-full-reassembly-feature",
|
||||
"ip4-sv-reassembly-feature"),
|
||||
};
|
||||
|
||||
VNET_FEATURE_INIT (trace_filtering6, static) = {
|
||||
.arc_name = "ip6-unicast",
|
||||
.node_name = "trace-filtering",
|
||||
.runs_after = VNET_FEATURES ("ip6-full-reassembly-feature",
|
||||
"ip6-sv-reassembly-feature"),
|
||||
};
|
||||
|
||||
VNET_FEATURE_INIT (pcap_filtering4, static) = {
|
||||
.arc_name = "ip4-unicast",
|
||||
.node_name = "pcap-filtering",
|
||||
.runs_after = VNET_FEATURES ("ip4-full-reassembly-feature",
|
||||
"ip4-sv-reassembly-feature"),
|
||||
};
|
||||
|
||||
VNET_FEATURE_INIT (pcap_filtering6, static) = {
|
||||
.arc_name = "ip6-unicast",
|
||||
.node_name = "pcap-filtering",
|
||||
.runs_after = VNET_FEATURES ("ip6-full-reassembly-feature",
|
||||
"ip6-sv-reassembly-feature"),
|
||||
};
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
31
src/plugins/tracenode/plugin.c
Normal file
31
src/plugins/tracenode/plugin.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <vlib/vlib.h>
|
||||
#include <vnet/plugin/plugin.h>
|
||||
#include <vpp/app/version.h>
|
||||
|
||||
VLIB_PLUGIN_REGISTER () = {
|
||||
.version = VPP_BUILD_VER,
|
||||
.description = "Tracing packet node",
|
||||
};
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
93
src/plugins/tracenode/test.c
Normal file
93
src/plugins/tracenode/test.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <vat/vat.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <vppinfra/error.h>
|
||||
#include <vnet/api_errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define __plugin_msg_base tracenode_test_main.msg_id_base
|
||||
#include <vlibapi/vat_helper_macros.h>
|
||||
|
||||
/* Declare message IDs */
|
||||
#include <tracenode/tracenode.api_enum.h>
|
||||
#include <tracenode/tracenode.api_types.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* API message ID base */
|
||||
u16 msg_id_base;
|
||||
vat_main_t *vat_main;
|
||||
} tracenode_test_main_t;
|
||||
|
||||
tracenode_test_main_t tracenode_test_main;
|
||||
|
||||
int
|
||||
api_tracenode_enable_disable (vat_main_t *vam)
|
||||
{
|
||||
unformat_input_t *i = vam->input;
|
||||
vl_api_tracenode_enable_disable_t *mp;
|
||||
u32 sw_if_index;
|
||||
bool is_pcap, enable;
|
||||
|
||||
sw_if_index = ~0;
|
||||
is_pcap = false;
|
||||
enable = true;
|
||||
|
||||
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (i, "disable"))
|
||||
enable = 0;
|
||||
else if (unformat (i, "pcap"))
|
||||
is_pcap = 1;
|
||||
else if (unformat (i, "%U", unformat_vnet_sw_interface, vnet_get_main (),
|
||||
&sw_if_index))
|
||||
{
|
||||
if (sw_if_index == 0)
|
||||
{
|
||||
clib_warning ("Local interface not supported...");
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
clib_warning ("Unknown input: %U\n", format_unformat_error, i);
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
M (TRACENODE_ENABLE_DISABLE, mp);
|
||||
mp->sw_if_index = htonl (sw_if_index);
|
||||
mp->is_pcap = is_pcap;
|
||||
mp->enable = enable;
|
||||
|
||||
int ret = 0;
|
||||
S (mp);
|
||||
W (ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include <tracenode/tracenode.api_test.c>
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
42
src/plugins/tracenode/tracenode.api
Normal file
42
src/plugins/tracenode/tracenode.api
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
option version = "0.1.0";
|
||||
|
||||
import "vnet/interface_types.api";
|
||||
|
||||
/** \brief Enable/disable trace filtering feature
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface on which to enable/disable trace filtering feature
|
||||
@param is_pcap - if non-zero enable the feature for pcap capture, else for trace
|
||||
@param enable - if non-zero then enable the feature, else disable it
|
||||
*/
|
||||
autoreply define tracenode_enable_disable
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
bool is_pcap [default=false];
|
||||
bool enable [default=true];
|
||||
|
||||
option vat_help = "tracenode_enable_disable <intfc> [disable] [pcap]";
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
71
src/plugins/tracenode/tracenode.c
Normal file
71
src/plugins/tracenode/tracenode.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <vlib/vlib.h>
|
||||
#include <tracenode/tracenode.h>
|
||||
|
||||
tracenode_main_t tracenode_main;
|
||||
|
||||
int
|
||||
tracenode_feature_enable_disable (u32 sw_if_index, bool is_pcap, bool enable)
|
||||
{
|
||||
tracenode_main_t *tnm = &tracenode_main;
|
||||
char *node_name = is_pcap ? "pcap-filtering" : "trace-filtering";
|
||||
int rv = 0;
|
||||
|
||||
if (pool_is_free_index (tnm->vnet_main->interface_main.sw_interfaces,
|
||||
sw_if_index))
|
||||
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||
|
||||
if (clib_bitmap_get (tnm->feature_enabled_by_sw_if, sw_if_index) == enable)
|
||||
return 0;
|
||||
|
||||
if ((rv = vnet_feature_enable_disable ("ip4-unicast", node_name, sw_if_index,
|
||||
enable, 0, 0)) != 0)
|
||||
return rv;
|
||||
|
||||
if ((rv = vnet_feature_enable_disable ("ip6-unicast", node_name, sw_if_index,
|
||||
enable, 0, 0)) != 0)
|
||||
return rv;
|
||||
|
||||
tnm->feature_enabled_by_sw_if =
|
||||
clib_bitmap_set (tnm->feature_enabled_by_sw_if, sw_if_index, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
tracenode_init (vlib_main_t *vm)
|
||||
{
|
||||
tracenode_main_t *tnm = &tracenode_main;
|
||||
clib_error_t *error = 0;
|
||||
|
||||
memset (tnm, 0, sizeof (*tnm));
|
||||
|
||||
tnm->vnet_main = vnet_get_main ();
|
||||
|
||||
error = tracenode_plugin_api_hookup (vm);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
VLIB_INIT_FUNCTION (tracenode_init);
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
43
src/plugins/tracenode/tracenode.h
Normal file
43
src/plugins/tracenode/tracenode.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
#ifndef _TRACENODE_H_
|
||||
#define _TRACENODE_H_
|
||||
#include <vlib/vlib.h>
|
||||
#include <vnet/feature/feature.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vnet_main_t *vnet_main;
|
||||
uword *feature_enabled_by_sw_if;
|
||||
u16 msg_id_base;
|
||||
} tracenode_main_t;
|
||||
|
||||
extern tracenode_main_t tracenode_main;
|
||||
|
||||
clib_error_t *tracenode_plugin_api_hookup (vlib_main_t *vm);
|
||||
|
||||
int tracenode_feature_enable_disable (u32 sw_if_index, bool is_pcap,
|
||||
bool enable);
|
||||
|
||||
#endif /* _TRACENODE_H_ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -1,32 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import unittest
|
||||
import secrets
|
||||
import socket
|
||||
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath
|
||||
from vpp_ipip_tun_interface import VppIpIpTunInterface
|
||||
from vpp_papi import VppEnum
|
||||
from vpp_ipsec import VppIpsecSA, VppIpsecSpd, VppIpsecSpdItfBinding, VppIpsecSpdEntry
|
||||
from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
|
||||
|
||||
from scapy.contrib.geneve import GENEVE
|
||||
from scapy.packet import Raw
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from scapy.layers.inet import IP, UDP, TCP
|
||||
from scapy.layers.vxlan import VXLAN
|
||||
from scapy.layers.ipsec import ESP, SecurityAssociation
|
||||
from scapy.compat import raw
|
||||
from scapy.utils import rdpcap
|
||||
|
||||
|
||||
class TestTracefilter(VppTestCase):
|
||||
"""Packet Tracer Filter Test"""
|
||||
|
||||
class TemplateTraceFilter(VppTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestTracefilter, cls).setUpClass()
|
||||
super().setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestTracefilter, cls).tearDownClass()
|
||||
super().tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
super(TestTracefilter, self).setUp()
|
||||
super().setUp()
|
||||
self.create_pg_interfaces(range(2))
|
||||
self.pg0.generate_remote_hosts(11)
|
||||
for i in self.pg_interfaces:
|
||||
@@ -35,7 +39,7 @@ class TestTracefilter(VppTestCase):
|
||||
i.resolve_arp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestTracefilter, self).tearDown()
|
||||
super().tearDown()
|
||||
for i in self.pg_interfaces:
|
||||
i.unconfig()
|
||||
i.admin_down()
|
||||
@@ -56,9 +60,12 @@ class TestTracefilter(VppTestCase):
|
||||
r = self.cli("show classify table verbose")
|
||||
self.assertTrue(r.reply.find("hits %i" % n) != -1)
|
||||
|
||||
def clear(self):
|
||||
self.cli("clear trace")
|
||||
|
||||
def add_trace_filter(self, mask, match):
|
||||
self.cli("classify filter trace mask %s match %s" % (mask, match))
|
||||
self.cli("clear trace")
|
||||
self.clear()
|
||||
self.cli("trace add pg-input 1000 filter")
|
||||
|
||||
def del_trace_filters(self):
|
||||
@@ -73,6 +80,17 @@ class TestTracefilter(VppTestCase):
|
||||
s = "pcap rx/tx/drop: first table none"
|
||||
self.assertTrue(r.reply.find(s) != -1)
|
||||
|
||||
# install a classify rule, inject traffic and check for hits
|
||||
def assert_classify(self, mask, match, packets, n=None):
|
||||
self.add_trace_filter("hex %s" % mask, "hex %s" % match)
|
||||
self.send_and_expect(self.pg0, packets, self.pg1, trace=False)
|
||||
self.assert_hits(n if n is not None else len(packets))
|
||||
self.del_trace_filters()
|
||||
|
||||
|
||||
class TestTracefilter(TemplateTraceFilter):
|
||||
"""Packet Tracer Filter Test"""
|
||||
|
||||
def test_basic(self):
|
||||
"""Packet Tracer Filter Test"""
|
||||
self.add_trace_filter(
|
||||
@@ -111,13 +129,6 @@ class TestTracefilter(VppTestCase):
|
||||
|
||||
self.del_trace_filters()
|
||||
|
||||
# install a classify rule, inject traffic and check for hits
|
||||
def assert_classify(self, mask, match, packets, n=None):
|
||||
self.add_trace_filter("hex %s" % mask, "hex %s" % match)
|
||||
self.send_and_expect(self.pg0, packets, self.pg1, trace=False)
|
||||
self.assert_hits(n if n is not None else len(packets))
|
||||
self.del_trace_filters()
|
||||
|
||||
def test_encap(self):
|
||||
"""Packet Tracer Filter Test with encap"""
|
||||
|
||||
@@ -281,5 +292,176 @@ class TestTracefilter(VppTestCase):
|
||||
self.assertEqual(len(pcap), 17)
|
||||
|
||||
|
||||
class TestTraceFilterInner(TemplateTraceFilter):
|
||||
"""Packet Tracer Filter Inner Test"""
|
||||
|
||||
extra_vpp_plugin_config = [
|
||||
"plugin tracenode_plugin.so {enable}",
|
||||
]
|
||||
|
||||
def add_trace_filter(self, mask, match, tn_feature_intfc_index=None):
|
||||
if tn_feature_intfc_index is not None:
|
||||
self.logger.info("fffff")
|
||||
self.vapi.tracenode_enable_disable(sw_if_index=tn_feature_intfc_index)
|
||||
super().add_trace_filter(mask, match)
|
||||
|
||||
def del_trace_filters(self, tn_feature_intfc_index=None):
|
||||
if tn_feature_intfc_index is not None:
|
||||
self.vapi.tracenode_enable_disable(
|
||||
sw_if_index=tn_feature_intfc_index, enable=False
|
||||
)
|
||||
super().del_trace_filters()
|
||||
|
||||
def __add_sa(self, id_, tun_src, tun_dst):
|
||||
# AES-CTR-128 / SHA2-256
|
||||
crypto_key_length = 16
|
||||
salt_length = 4
|
||||
integ_key_lenght = 16
|
||||
crypto_key = secrets.token_bytes(crypto_key_length)
|
||||
salt = secrets.randbits(salt_length * 8)
|
||||
integ_key = secrets.token_bytes(integ_key_lenght)
|
||||
|
||||
flags = VppEnum.vl_api_ipsec_sad_flags_t.IPSEC_API_SAD_FLAG_UDP_ENCAP
|
||||
|
||||
vpp_sa_in = VppIpsecSA(
|
||||
test=self,
|
||||
id=id_,
|
||||
spi=id_,
|
||||
integ_alg=VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA_256_128,
|
||||
integ_key=integ_key,
|
||||
crypto_alg=VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CTR_128,
|
||||
crypto_key=crypto_key,
|
||||
proto=VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
|
||||
flags=flags,
|
||||
salt=salt,
|
||||
tun_src=tun_src,
|
||||
tun_dst=tun_dst,
|
||||
udp_src=4500,
|
||||
udp_dst=4500,
|
||||
)
|
||||
vpp_sa_in.add_vpp_config()
|
||||
|
||||
scapy_sa_in = SecurityAssociation(
|
||||
ESP,
|
||||
spi=id_,
|
||||
crypt_algo="AES-CTR",
|
||||
crypt_key=crypto_key + salt.to_bytes(salt_length, "big"),
|
||||
auth_algo="SHA2-256-128",
|
||||
auth_key=integ_key,
|
||||
tunnel_header=IP(src=tun_src, dst=tun_dst),
|
||||
nat_t_header=UDP(sport=4500, dport=4500),
|
||||
)
|
||||
|
||||
id_ += 1
|
||||
|
||||
vpp_sa_out = VppIpsecSA(
|
||||
test=self,
|
||||
id=id_,
|
||||
spi=id_,
|
||||
integ_alg=VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA_256_128,
|
||||
integ_key=integ_key,
|
||||
crypto_alg=VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CTR_128,
|
||||
crypto_key=crypto_key,
|
||||
proto=VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
|
||||
flags=flags,
|
||||
salt=salt,
|
||||
tun_src=tun_dst,
|
||||
tun_dst=tun_src,
|
||||
udp_src=4500,
|
||||
udp_dst=4500,
|
||||
)
|
||||
vpp_sa_out.add_vpp_config()
|
||||
|
||||
scapy_sa_out = SecurityAssociation(
|
||||
ESP,
|
||||
spi=id_,
|
||||
crypt_algo="AES-CTR",
|
||||
crypt_key=crypto_key + salt.to_bytes(salt_length, "big"),
|
||||
auth_algo="SHA2-256-128",
|
||||
auth_key=integ_key,
|
||||
tunnel_header=IP(src=tun_dst, dst=tun_src),
|
||||
nat_t_header=UDP(sport=4500, dport=4500),
|
||||
)
|
||||
|
||||
return vpp_sa_in, scapy_sa_in, vpp_sa_out, scapy_sa_out
|
||||
|
||||
def __gen_encrypt_pkt(self, scapy_sa, pkt):
|
||||
return Ether(
|
||||
src=self.pg0.local_mac, dst=self.pg0.remote_mac
|
||||
) / scapy_sa.encrypt(pkt)
|
||||
|
||||
def test_encrypted_encap(self):
|
||||
"""Packet Tracer Filter Test with encrypted encap"""
|
||||
|
||||
vpp_sa_in, scapy_sa_in, vpp_sa_out, _ = self.__add_sa(
|
||||
1, self.pg0.local_ip4, self.pg0.remote_ip4
|
||||
)
|
||||
|
||||
spd = VppIpsecSpd(self, 1)
|
||||
spd.add_vpp_config()
|
||||
|
||||
spd_binding = VppIpsecSpdItfBinding(self, spd, self.pg0)
|
||||
spd_binding.add_vpp_config()
|
||||
|
||||
spd_entry = VppIpsecSpdEntry(
|
||||
self,
|
||||
spd,
|
||||
1,
|
||||
self.pg0.local_ip4,
|
||||
self.pg0.local_ip4,
|
||||
self.pg0.remote_ip4,
|
||||
self.pg0.remote_ip4,
|
||||
socket.IPPROTO_ESP,
|
||||
policy=VppEnum.vl_api_ipsec_spd_action_t.IPSEC_API_SPD_ACTION_PROTECT,
|
||||
is_outbound=0,
|
||||
).add_vpp_config()
|
||||
|
||||
# the inner packet we are trying to match
|
||||
inner_pkt = (
|
||||
IP(src=self.pg1.local_ip4, dst=self.pg1.remote_ip4)
|
||||
/ TCP(sport=1234, dport=4321)
|
||||
/ Raw(b"\xa5" * 100)
|
||||
)
|
||||
pkt = self.__gen_encrypt_pkt(scapy_sa_in, inner_pkt)
|
||||
|
||||
# self.add_trace_filter("l3 ip4 src", f"l3 ip4 src {self.pg0.local_ip4}")
|
||||
|
||||
self.add_trace_filter(
|
||||
"l2 none l3 ip4 src proto l4 dst_port",
|
||||
f"l2 none l3 ip4 src {self.pg1.local_ip4} proto 6 l4 dst_port 4321",
|
||||
tn_feature_intfc_index=self.pg0.sw_if_index,
|
||||
)
|
||||
|
||||
self.logger.info("Sending packet with matching inner")
|
||||
self.send_and_expect(self.pg0, pkt * 67, self.pg1, trace=False)
|
||||
self.assert_hits(67)
|
||||
self.clear()
|
||||
|
||||
self.logger.info("Sending packet with wrong inner port")
|
||||
inner_pkt[TCP].dport = 1111
|
||||
pkt = self.__gen_encrypt_pkt(scapy_sa_in, inner_pkt)
|
||||
self.send_and_expect(self.pg0, pkt * 67, self.pg1, trace=False)
|
||||
# the classify session should still have the 67 previous hits.
|
||||
# In another way, the delta is 0
|
||||
self.assert_hits(67)
|
||||
self.clear()
|
||||
|
||||
self.logger.info("Sending packet with wrong source address")
|
||||
inner_pkt[IP].src = "1.2.3.4"
|
||||
inner_pkt[TCP].dport = 4321
|
||||
pkt = self.__gen_encrypt_pkt(scapy_sa_in, inner_pkt)
|
||||
self.send_and_expect(self.pg0, pkt * 67, self.pg1, trace=False)
|
||||
self.assert_hits(67)
|
||||
self.clear()
|
||||
|
||||
self.del_trace_filters(tn_feature_intfc_index=self.pg0.sw_if_index)
|
||||
|
||||
spd_entry.remove_vpp_config()
|
||||
spd_binding.remove_vpp_config()
|
||||
spd.remove_vpp_config()
|
||||
vpp_sa_in.remove_vpp_config()
|
||||
vpp_sa_out.remove_vpp_config()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
|
||||
Reference in New Issue
Block a user