diff options
Diffstat (limited to 'flowtable/0002-Add-Port-Mirroring-feature.patch')
-rw-r--r-- | flowtable/0002-Add-Port-Mirroring-feature.patch | 896 |
1 files changed, 896 insertions, 0 deletions
diff --git a/flowtable/0002-Add-Port-Mirroring-feature.patch b/flowtable/0002-Add-Port-Mirroring-feature.patch new file mode 100644 index 0000000..270a487 --- /dev/null +++ b/flowtable/0002-Add-Port-Mirroring-feature.patch @@ -0,0 +1,896 @@ +From ea8b126e31ab0f4e2c980be43cb423d50b7d7244 Mon Sep 17 00:00:00 2001 +From: Gabriel Ganne <gabriel.ganne@qosmos.com> +Date: Sat, 17 Sep 2016 10:13:52 +0200 +Subject: [PATCH 2/3] Add Port Mirroring feature + +port-mirroring is under /plugins +connect l2-input-classify node to the port-mirroring node +connect l2-output-classify node to the port-mirroring node + +next node depends on previous node. + +Author: Christophe Fontaine <christophe.fontaine@qosmos.com> +Author: Gabriel Ganne <gabriel.ganne@qosmos.com> + +Signed-off-by: Gabriel Ganne <gabriel.ganne@qosmos.com> +Change-Id: Ia8b83615880ca274ee6b292e4fea0eb02d4d7aaa +--- + plugins/Makefile.am | 4 + + plugins/configure.ac | 1 + + plugins/portmirroring-plugin/Makefile.am | 59 +++++++ + plugins/portmirroring-plugin/configure.ac | 16 ++ + plugins/portmirroring-plugin/portmirroring/api.c | 131 +++++++++++++++ + .../portmirroring-plugin/portmirroring/flowdata.h | 1 + + .../portmirroring/port_mirroring.c | 134 ++++++++++++++++ + .../portmirroring/port_mirroring.h | 67 ++++++++ + .../portmirroring/port_mirroring_in_node.c | 178 +++++++++++++++++++++ + .../portmirroring/port_mirroring_out_node.c | 168 +++++++++++++++++++ + .../portmirroring/portmirroring.api | 21 +++ + 11 files changed, 780 insertions(+) + create mode 100644 plugins/portmirroring-plugin/Makefile.am + create mode 100644 plugins/portmirroring-plugin/configure.ac + create mode 100644 plugins/portmirroring-plugin/portmirroring/api.c + create mode 120000 plugins/portmirroring-plugin/portmirroring/flowdata.h + create mode 100644 plugins/portmirroring-plugin/portmirroring/port_mirroring.c + create mode 100644 plugins/portmirroring-plugin/portmirroring/port_mirroring.h + create mode 100644 plugins/portmirroring-plugin/portmirroring/port_mirroring_in_node.c + create mode 100644 plugins/portmirroring-plugin/portmirroring/port_mirroring_out_node.c + create mode 100644 plugins/portmirroring-plugin/portmirroring/portmirroring.api + +diff --git a/plugins/Makefile.am b/plugins/Makefile.am +index d0a2e3c..7bd93a9 100644 +--- a/plugins/Makefile.am ++++ b/plugins/Makefile.am +@@ -55,3 +55,7 @@ endif + if ENABLE_flowtable_PLUGIN + SUBDIRS += flowtable-plugin + endif ++ ++if ENABLE_portmirroring_PLUGIN ++SUBDIRS += portmirroring-plugin ++endif +diff --git a/plugins/configure.ac b/plugins/configure.ac +index cbb180f..5e30011 100644 +--- a/plugins/configure.ac ++++ b/plugins/configure.ac +@@ -59,6 +59,7 @@ PLUGIN_ENABLED(snat) + PLUGIN_ENABLED(ila) + PLUGIN_ENABLED(lb) + PLUGIN_ENABLED(flowtable) ++PLUGIN_ENABLED(portmirroring) + + # Disabled plugins, require --enable-XXX-plugin + PLUGIN_DISABLED(vcgn) +diff --git a/plugins/portmirroring-plugin/Makefile.am b/plugins/portmirroring-plugin/Makefile.am +new file mode 100644 +index 0000000..77da992 +--- /dev/null ++++ b/plugins/portmirroring-plugin/Makefile.am +@@ -0,0 +1,59 @@ ++# Copyright (c) 2016 Cisco Systems, Inc. ++# 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. ++ ++AUTOMAKE_OPTIONS = foreign subdir-objects ++ ++AM_CFLAGS = -Wall ++AM_LDFLAGS = -module -shared -avoid-version ++ ++vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins ++vpppluginsdir = ${libdir}/vpp_plugins ++ ++# vppapitestplugins_LTLIBRARIES = portmirroring_test_plugin.la ++vppplugins_LTLIBRARIES = portmirroring_plugin.la ++ ++portmirroring_plugin_la_SOURCES = \ ++ portmirroring/api.c \ ++ portmirroring/port_mirroring.c \ ++ portmirroring/port_mirroring_in_node.c \ ++ portmirroring/port_mirroring_out_node.c ++ ++BUILT_SOURCES = portmirroring/portmirroring.api.h portmirroring/portmirroring.py ++ ++SUFFIXES = .api.h .api ++ ++%.api.h: %.api ++ mkdir -p `dirname $@` ; \ ++ $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ ++ | vppapigen --input - --output $@ --show-name $@ ++ ++%.py: %.api ++ $(info Creating Python binding for $@) ++ $(CC) $(CPPFLAGS) -E -P -C -x c $< \ ++ | vppapigen --input - --python - \ ++ | pyvppapigen.py --input - > $@ ++ ++ ++pyapidir = ${prefix}/vpp_papi_plugins ++pyapi_DATA = portmirroring/portmirroring.py ++ ++noinst_HEADERS = portmirroring/port_mirroring.h portmirroring/portmirroring.api.h ++ ++#portmirroring_test_plugin_la_SOURCES = \ ++# portmirroring/portmirroring_test.c portmirroring/portmirroring_plugin.api.h ++ ++# Remove *.la files ++install-data-hook: ++ @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) ++ ++# @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) +diff --git a/plugins/portmirroring-plugin/configure.ac b/plugins/portmirroring-plugin/configure.ac +new file mode 100644 +index 0000000..3af74c0 +--- /dev/null ++++ b/plugins/portmirroring-plugin/configure.ac +@@ -0,0 +1,16 @@ ++AC_INIT(pm_plugin, 1.0) ++AM_INIT_AUTOMAKE ++AM_SILENT_RULES([yes]) ++AC_PREFIX_DEFAULT([/usr]) ++ ++AC_PROG_LIBTOOL ++AC_PROG_CC ++ ++AC_ARG_WITH(dpdk, ++ AC_HELP_STRING([--with-dpdk],[Use the Intel dpdk]), ++ [with_dpdk=1], ++ [with_dpdk=0]) ++ ++AM_CONDITIONAL(WITH_DPDK, test "$with_dpdk" = "1") ++AM_COND_IF(WITH_DPDK, CFLAGS+="-DDPDK=1") ++AC_OUTPUT([Makefile]) +diff --git a/plugins/portmirroring-plugin/portmirroring/api.c b/plugins/portmirroring-plugin/portmirroring/api.c +new file mode 100644 +index 0000000..696557b +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/api.c +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (c) 2016 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 <portmirroring/port_mirroring.h> ++ ++#include <vppinfra/byte_order.h> ++#include <vlibapi/api.h> ++#include <vlibmemory/api.h> ++#include <vlibsocket/api.h> ++ ++#define vl_msg_id(n,h) n, ++typedef enum { ++#include <portmirroring/portmirroring.api.h> ++ /* We'll want to know how many messages IDs we need... */ ++ VL_MSG_FIRST_AVAILABLE, ++} vl_msg_id_t; ++#undef vl_msg_id ++ ++ ++/* define message structures */ ++#define vl_typedefs ++#include <portmirroring/portmirroring.api.h> ++#undef vl_typedefs ++ ++/* define generated endian-swappers */ ++#define vl_endianfun ++#include <portmirroring/portmirroring.api.h> ++#undef vl_endianfun ++ ++#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) ++ ++/* Get the API version number */ ++#define vl_api_version(n,v) static u32 api_version=(v); ++#include <portmirroring/portmirroring.api.h> ++#undef vl_api_version ++ ++/* Macro to finish up custom dump fns */ ++#define FINISH \ ++ vec_add1 (s, 0); \ ++ vl_print (handle, (char *)s); \ ++ vec_free (s); \ ++ return handle; ++ ++/* ++ * A handy macro to set up a message reply. ++ * Assumes that the following variables are available: ++ * mp - pointer to request message ++ * rmp - pointer to reply message type ++ * rv - return value ++ */ ++ ++#define REPLY_MACRO(t) \ ++do { \ ++ unix_shared_memory_queue_t * q = \ ++ vl_api_client_index_to_input_queue (mp->client_index); \ ++ if (!q) \ ++ return; \ ++ \ ++ rmp = vl_msg_api_alloc (sizeof (*rmp)); \ ++ rmp->_vl_msg_id = ntohs((t)+pmm->msg_id_base); \ ++ rmp->context = mp->context; \ ++ rmp->retval = ntohl(rv); \ ++ \ ++ vl_msg_api_send_shmem (q, (u8 *)&rmp); \ ++} while(0); ++ ++static void ++vl_api_pm_conf_t_handler ++(vl_api_pm_conf_t * mp) ++{ ++ pm_main_t *pmm = &pm_main; ++ vl_api_pm_conf_reply_t * rmp; ++ int rv = 0; ++ ++ rv = pm_conf(mp->dst_interface, mp->from_node, mp->is_del); ++ ++ REPLY_MACRO (VL_API_PM_CONF_REPLY); ++} ++ ++static void *vl_api_pm_conf_t_print ++(vl_api_pm_conf_t *mp, void * handle) ++{ ++ u8 * s; ++ s = format (0, "SCRIPT: pm_conf "); ++ s = format (s, "%u ", mp->dst_interface); ++ s = format (s, "%u ", mp->from_node); ++ s = format (s, "%s ", (mp->is_del? "DELETE" : "ADD" )); ++ FINISH; ++} ++ ++ ++/* List of message types that this plugin understands */ ++#define foreach_pm_plugin_api_msg \ ++_(PM_CONF, pm_conf) \ ++ ++ ++static clib_error_t * pm_api_init (vlib_main_t * vm) ++{ ++ pm_main_t *pmm = &pm_main; ++ u8 *name = format (0, "portmirroring_%08x%c", api_version, 0); ++ pmm->msg_id_base = vl_msg_api_get_msg_ids ++ ((char *) name, VL_MSG_FIRST_AVAILABLE); ++ ++#define _(N,n) \ ++ vl_msg_api_set_handlers((VL_API_##N + pmm->msg_id_base), \ ++ #n, \ ++ vl_api_##n##_t_handler, \ ++ vl_noop_handler, \ ++ vl_api_##n##_t_endian, \ ++ vl_api_##n##_t_print, \ ++ sizeof(vl_api_##n##_t), 1); ++ foreach_pm_plugin_api_msg; ++#undef _ ++ ++ return 0; ++} ++ ++VLIB_INIT_FUNCTION (pm_api_init); ++ +diff --git a/plugins/portmirroring-plugin/portmirroring/flowdata.h b/plugins/portmirroring-plugin/portmirroring/flowdata.h +new file mode 120000 +index 0000000..67f4f12 +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/flowdata.h +@@ -0,0 +1 @@ ++../../flowtable-plugin/flowtable/flowdata.h +\ No newline at end of file +diff --git a/plugins/portmirroring-plugin/portmirroring/port_mirroring.c b/plugins/portmirroring-plugin/portmirroring/port_mirroring.c +new file mode 100644 +index 0000000..46b6e0f +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/port_mirroring.c +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (c) 2015 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. ++ */ ++ ++#if DPDK != 1 ++#error "DPDK needed" ++#endif ++ ++#include <vnet/plugin/plugin.h> ++#include <vnet/api_errno.h> ++#include <portmirroring/port_mirroring.h> ++ ++int pm_conf(u8 dst_interface, u8 from_node, u8 is_del) ++{ ++ pm_main_t *pm = &pm_main; ++ ++ if(is_del == 0) { ++ pm->sw_if_index = dst_interface; ++ pm->from_node = from_node; ++ if (from_node == PM_FROM_FLOWTABLE) { ++ pm->next_node_index = PM_IN_HIT_NEXT_ETHERNET_INPUT; ++ } else if (from_node == PM_FROM_CLASSSIFIER) { ++ pm->next_node_index = PM_IN_HIT_NEXT_L2_LEARN; ++ } else { ++ pm->next_node_index = PM_IN_HIT_NEXT_ERROR; ++ return -1; ++ } ++ } else { ++ pm->sw_if_index = ~0; ++ pm->from_node = ~0; ++ pm->next_node_index = ~0; ++ } ++ ++ return 0; ++} ++ ++static clib_error_t * ++set_pm_command_fn (vlib_main_t * vm, ++ unformat_input_t * input, vlib_cli_command_t * cmd) ++{ ++ pm_main_t *pm = &pm_main; ++ int enable_disable = 1; ++ int sw_if_index = ~0; ++ int from_node = ~0; ++ ++ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) ++ { ++ if (unformat (input, "from %U", unformat_vlib_node, ++ pm->vnet_main, &from_node)); ++ if (unformat (input, "to %U", unformat_vnet_sw_interface, ++ pm->vnet_main, &sw_if_index)); ++ else if (unformat (input, "del")) ++ enable_disable = 0; ++ else if (unformat (input, "disable")) ++ enable_disable = 0; ++ else ++ break; ++ } ++ ++ if (sw_if_index == ~0) ++ return clib_error_return (0, "interface required"); ++ if (from_node == ~0) ++ return clib_error_return (0, "previous node required"); ++ ++ ++ if (enable_disable) ++ { ++ pm->sw_if_index = sw_if_index; ++ pm->from_node = from_node; ++ return 0; ++ } ++ else ++ { ++ pm->sw_if_index = ~0; ++ pm->from_node = ~0; ++ } ++ ++ ++ return 0; ++} ++ ++VLIB_CLI_COMMAND (set_pm_command, static) = ++{ ++ .path = "set pm", ++ .short_help = "set pm from <0|1> to <intfc> [del]", ++ .function = set_pm_command_fn, ++}; ++ ++ ++static clib_error_t * ++pm_init (vlib_main_t * vm) ++{ ++ pm_main_t *pm = &pm_main; ++ ++ pm->sw_if_index = ~0; ++ pm->from_node = ~0; ++ ++ pm->pm_in_hit_node_index = pm_in_hit_node.index; ++ pm->pm_out_hit_node_index = pm_out_hit_node.index; ++ ++ /* pm-out previous node */ ++ u32 l2out_classify_idx = vlib_get_node_by_name(vm, (u8*) "l2-output-classify")->index; ++ vlib_node_add_next(vm, l2out_classify_idx, pm->pm_out_hit_node_index); ++ ++ /* pm-in & pm-out next node */ ++ pm->interface_output_node_index = vlib_get_node_by_name(vm, (u8*) "interface-output")->index; ++ ++ return 0; ++} ++ ++VLIB_INIT_FUNCTION (pm_init); ++ ++clib_error_t * ++vlib_plugin_register (vlib_main_t * vm, ++ vnet_plugin_handoff_t * h, ++ int from_early_init) ++{ ++ clib_error_t *error = 0; ++ pm_main_t *pm = &pm_main; ++ pm->vnet_main = vnet_get_main(); ++ pm->vlib_main = vm; ++ return error; ++} +diff --git a/plugins/portmirroring-plugin/portmirroring/port_mirroring.h b/plugins/portmirroring-plugin/portmirroring/port_mirroring.h +new file mode 100644 +index 0000000..8e9826f +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/port_mirroring.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (c) 2015 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 __port_mirroring_h__ ++#define __port_mirroring_h__ ++ ++#include <vnet/vnet.h> ++#include <vnet/ip/ip.h> ++ ++enum { ++ PM_FROM_CLASSSIFIER = 0, ++ PM_FROM_FLOWTABLE = 1, ++ PM_FROM_MAX ++}; ++ ++typedef enum { ++ PM_IN_HIT_NEXT_ERROR, ++ PM_IN_HIT_NEXT_ETHERNET_INPUT, ++ PM_IN_HIT_NEXT_L2_LEARN, ++ PM_IN_HIT_N_NEXT, ++} pm_in_hit_next_t; ++ ++typedef struct ++{ ++ /* mirror interface index */ ++ u32 sw_if_index; ++ u32 from_node; ++ ++ /* Hit node index */ ++ u32 pm_in_hit_node_index; ++ u32 pm_out_hit_node_index; ++ ++ u32 interface_output_node_index; ++ ++ /* depends on the previous node */ ++ u32 next_node_index; ++ ++ /* convenience */ ++ vlib_main_t *vlib_main; ++ vnet_main_t *vnet_main; ++ ++ /** ++ * API dynamically registered base ID. ++ */ ++ u16 msg_id_base; ++} pm_main_t; ++ ++pm_main_t pm_main; ++ ++int pm_conf(u8 dst_interface, u8 from_node, u8 is_del); ++ ++extern vlib_node_registration_t pm_in_hit_node; ++extern vlib_node_registration_t pm_out_hit_node; ++ ++#endif /* __port_mirroring_h__ */ +diff --git a/plugins/portmirroring-plugin/portmirroring/port_mirroring_in_node.c b/plugins/portmirroring-plugin/portmirroring/port_mirroring_in_node.c +new file mode 100644 +index 0000000..04b05df +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/port_mirroring_in_node.c +@@ -0,0 +1,178 @@ ++/* ++ * Copyright (c) 2015 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/vnet.h> ++#include <vppinfra/error.h> ++ ++#if DPDK != 1 ++#error "DPDK needed" ++#endif ++ ++#include <portmirroring/port_mirroring.h> ++#include <vnet/dpdk_replication.h> ++ ++#include <vppinfra/error.h> ++#include <vppinfra/elog.h> ++ ++#include "flowdata.h" ++#include "port_mirroring.h" ++ ++vlib_node_registration_t pm_in_hit_node; ++ ++typedef struct { ++ u32 next_index; ++} pm_in_hit_trace_t; ++ ++/* packet trace format function */ ++static u8 * ++format_pm_in_hit_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 *); ++ pm_in_hit_trace_t * t = va_arg(*args, pm_in_hit_trace_t *); ++ ++ s = format(s, "PM_IN_HIT: next index %d", t->next_index); ++ ++ return s; ++} ++ ++vlib_node_registration_t pm_in_hit_node; ++ ++#define foreach_pm_in_hit_error \ ++ _(HITS, "PM in packets processed") \ ++ _(NO_INTF_OUT, "No out interface configured") ++ ++typedef enum { ++#define _(sym, str) PM_IN_HIT_ERROR_ ## sym, ++ foreach_pm_in_hit_error ++#undef _ ++ PM_IN_HIT_N_ERROR, ++} pm_in_hit_error_t; ++ ++static char * pm_in_hit_error_strings[] = { ++#define _(sym, string) string, ++ foreach_pm_in_hit_error ++#undef _ ++}; ++ ++static uword ++pm_in_hit_node_fn(vlib_main_t * vm, ++ vlib_node_runtime_t * node, vlib_frame_t * frame) ++{ ++ u32 n_left_from, * from, * to_next; ++ u32 next_index; ++ vlib_frame_t * dup_frame = 0; ++ u32 * to_int_next = 0; ++ pm_main_t * pm = &pm_main; ++ ++ from = vlib_frame_vector_args(frame); ++ n_left_from = frame->n_vectors; ++ next_index = node->cached_next_index; ++ ++ if (pm->sw_if_index == ~0) { ++ vlib_node_increment_counter (vm, pm_in_hit_node.index, ++ PM_IN_HIT_ERROR_NO_INTF_OUT, ++ n_left_from); ++ } else { ++ /* The intercept frame... */ ++ dup_frame = vlib_get_frame_to_node(vm, pm->interface_output_node_index); ++ to_int_next = vlib_frame_vector_args(dup_frame); ++ } ++ ++ 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; ++ vlib_buffer_t * c0; ++ u32 next0 = pm->next_node_index; ++ ++ /* 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; ++ ++ b0 = vlib_get_buffer(vm, bi0); ++ if (PREDICT_TRUE(to_int_next != 0)) ++ { ++ /* Make a copy */ ++ c0 = vlib_dpdk_clone_buffer(vm, b0); ++ ++ vnet_buffer (c0)->sw_if_index[VLIB_TX] = pm->sw_if_index; ++ ++ to_int_next[0] = vlib_get_buffer_index(vm, c0); ++ to_int_next++; ++ ++ } ++ ++ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) ++ && (b0->flags & VLIB_BUFFER_IS_TRACED))) ++ { ++ pm_in_hit_trace_t * t = vlib_add_trace(vm, node, b0, sizeof(*t)); ++ t->next_index = next0; ++ } ++ ++ /* restore opaque value which was used by the flowtable plugin */ ++ if (pm->from_node == PM_FROM_FLOWTABLE) { ++ flow_data_t flow_data; ++ clib_memcpy(&flow_data, b0->opaque, sizeof(flow_data)); ++ vnet_buffer (b0)->sw_if_index[VLIB_RX] = flow_data.data.sw_if_index_current; ++ } ++ ++ /* verify speculative enqueue, maybe switch current next frame */ ++ 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); ++ } ++ ++ if (dup_frame) ++ { ++ dup_frame->n_vectors = frame->n_vectors; ++ vlib_put_frame_to_node(vm, pm->interface_output_node_index, dup_frame); ++ } ++ ++ vlib_node_increment_counter(vm, pm_in_hit_node.index, ++ PM_IN_HIT_ERROR_HITS, frame->n_vectors); ++ return frame->n_vectors; ++} ++ ++VLIB_REGISTER_NODE(pm_in_hit_node) = { ++ .function = pm_in_hit_node_fn, ++ .name = "pm-in-hit", ++ .vector_size = sizeof(u32), ++ .format_trace = format_pm_in_hit_trace, ++ .type = VLIB_NODE_TYPE_INTERNAL, ++ ++ .n_errors = ARRAY_LEN(pm_in_hit_error_strings), ++ .error_strings = pm_in_hit_error_strings, ++ ++ .n_next_nodes = PM_IN_HIT_N_NEXT, ++ .next_nodes = { ++ [PM_IN_HIT_NEXT_ERROR] = "error-drop", ++ [PM_IN_HIT_NEXT_ETHERNET_INPUT] = "ethernet-input", ++ [PM_IN_HIT_NEXT_L2_LEARN] = "l2-learn", ++ } ++}; +diff --git a/plugins/portmirroring-plugin/portmirroring/port_mirroring_out_node.c b/plugins/portmirroring-plugin/portmirroring/port_mirroring_out_node.c +new file mode 100644 +index 0000000..9eebb88 +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/port_mirroring_out_node.c +@@ -0,0 +1,168 @@ ++/* ++ * Copyright (c) 2015 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/vnet.h> ++#include <vppinfra/error.h> ++ ++#if DPDK != 1 ++#error "DPDK needed" ++#endif ++ ++#include <portmirroring/port_mirroring.h> ++#include <vnet/dpdk_replication.h> ++ ++#include <vppinfra/error.h> ++#include <vppinfra/elog.h> ++ ++vlib_node_registration_t pm_out_hit_node; ++ ++typedef struct { ++ u32 next_index; ++} pm_out_hit_trace_t; ++ ++/* packet trace format function */ ++static u8 * ++format_pm_out_hit_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 *); ++ pm_out_hit_trace_t * t = va_arg(*args, pm_out_hit_trace_t *); ++ ++ s = format(s, "PM_OUT_HIT: next index %d", t->next_index); ++ ++ return s; ++} ++ ++#define foreach_pm_out_hit_error \ ++ _(HITS, "PM out packets processed") \ ++ _(NO_COLLECTOR, "No collector configured") ++ ++typedef enum { ++#define _(sym, str) PM_OUT_HIT_ERROR_ ## sym, ++ foreach_pm_out_hit_error ++#undef _ ++ PM_OUT_HIT_N_ERROR, ++} pm_out_hit_error_t; ++ ++static char * pm_out_hit_error_strings[] = { ++#define _(sym, string) string, ++ foreach_pm_out_hit_error ++#undef _ ++}; ++ ++typedef enum { ++ PM_OUT_HIT_NEXT_IF_OUT, ++ PM_OUT_HIT_N_NEXT, ++} pm_out_hit_next_t; ++ ++static uword ++pm_out_hit_node_fn(vlib_main_t * vm, ++ vlib_node_runtime_t * node, vlib_frame_t * frame) ++{ ++ u32 n_left_from, * from, * to_next; ++ pm_out_hit_next_t next_index; ++ vlib_frame_t * dup_frame = 0; ++ u32 * to_int_next = 0; ++ pm_main_t * pm = &pm_main; ++ ++ from = vlib_frame_vector_args(frame); ++ n_left_from = frame->n_vectors; ++ next_index = node->cached_next_index; ++ ++ if (pm->sw_if_index == ~0) { ++ vlib_node_increment_counter (vm, pm_out_hit_node.index, ++ PM_OUT_HIT_ERROR_NO_COLLECTOR, ++ n_left_from); ++ } else { ++ /* The intercept frame... */ ++ dup_frame = vlib_get_frame_to_node(vm, pm->interface_output_node_index); ++ to_int_next = vlib_frame_vector_args(dup_frame); ++ } ++ ++ 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; ++ vlib_buffer_t * c0; ++ u32 next0 = PM_OUT_HIT_NEXT_IF_OUT; ++ ++ /* 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; ++ ++ b0 = vlib_get_buffer(vm, bi0); ++ if (PREDICT_TRUE(to_int_next != 0)) ++ { ++ /* Make an intercept copy */ ++ c0 = vlib_dpdk_clone_buffer(vm, b0); ++ ++ vnet_buffer (c0)->sw_if_index[VLIB_TX] = pm->sw_if_index; ++ ++ to_int_next[0] = vlib_get_buffer_index(vm, c0); ++ to_int_next++; ++ } ++ ++ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) ++ && (b0->flags & VLIB_BUFFER_IS_TRACED))) ++ { ++ pm_out_hit_trace_t * t = vlib_add_trace(vm, node, b0, sizeof(*t)); ++ t->next_index = next0; ++ } ++ /* verify speculative enqueue, maybe switch current next frame */ ++ 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); ++ } ++ ++ if (dup_frame) ++ { ++ dup_frame->n_vectors = frame->n_vectors; ++ vlib_put_frame_to_node(vm, pm->interface_output_node_index, dup_frame); ++ } ++ ++ vlib_node_increment_counter(vm, pm_out_hit_node.index, ++ PM_OUT_HIT_ERROR_HITS, frame->n_vectors); ++ return frame->n_vectors; ++} ++ ++VLIB_REGISTER_NODE(pm_out_hit_node) = { ++ .function = pm_out_hit_node_fn, ++ .name = "pm-out-hit", ++ .vector_size = sizeof(u32), ++ .format_trace = format_pm_out_hit_trace, ++ .type = VLIB_NODE_TYPE_INTERNAL, ++ ++ .n_errors = ARRAY_LEN(pm_out_hit_error_strings), ++ .error_strings = pm_out_hit_error_strings, ++ ++ .n_next_nodes = PM_OUT_HIT_N_NEXT, ++ ++ .next_nodes = { ++ [PM_OUT_HIT_NEXT_IF_OUT] = "interface-output", ++ } ++}; +diff --git a/plugins/portmirroring-plugin/portmirroring/portmirroring.api b/plugins/portmirroring-plugin/portmirroring/portmirroring.api +new file mode 100644 +index 0000000..fe86bb2 +--- /dev/null ++++ b/plugins/portmirroring-plugin/portmirroring/portmirroring.api +@@ -0,0 +1,21 @@ ++/** \brief Configure Port-Mirroring global parameters ++ @param client_index - opaque cookie to identify the sender ++ @param context - sender context, to match reply w/ request ++ @param dst_interface - name or id of interface to copy packets to ++ @param from_node - 0|1 (classifier|flowtable) ++ @param is_del - Whether we have to delete any port mirrring information ++*/ ++define pm_conf ++{ ++ u32 client_index; ++ u32 context; ++ u8 dst_interface; ++ u8 from_node; ++ u8 is_del; ++}; ++ ++define pm_conf_reply { ++ u32 context; ++ i32 retval; ++}; ++ +-- +2.10.0.rc1.15.g5cb0d5a + |