aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/adl/adl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/adl/adl.c')
-rw-r--r--src/plugins/adl/adl.c417
1 files changed, 417 insertions, 0 deletions
diff --git a/src/plugins/adl/adl.c b/src/plugins/adl/adl.c
new file mode 100644
index 00000000000..832bfd4a982
--- /dev/null
+++ b/src/plugins/adl/adl.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2016,2020 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 <vnet/ethernet/ethernet.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+#include <plugins/adl/adl.h>
+
+adl_main_t adl_main;
+
+static clib_error_t *
+adl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
+{
+ adl_main_t *am = &adl_main;
+ adl_config_data_t _data, *data = &_data;
+ vlib_main_t *vm = am->vlib_main;
+ vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);;
+ adl_config_main_t *acm;
+ int address_family;
+ u32 ci, default_next;
+
+ clib_memset (data, 0, sizeof (*data));
+
+ /*
+ * Ignore local interface, pg interfaces. $$$ need a #define for the
+ * first "real" interface. The answer is 5 at the moment.
+ */
+ if (hi->dev_class_index == vnet_local_interface_device_class.index)
+ return 0;
+
+ for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
+ address_family++)
+ {
+ acm = &am->adl_config_mains[address_family];
+
+ /*
+ * Once-only code to initialize the per-address-family
+ * adl feature subgraphs.
+ * Since the (single) start-node, adl-input, must be able
+ * to push pkts into three separate subgraphs, we
+ * use a unified adl_feature_type_t enumeration.
+ */
+
+ if (!(acm->config_main.node_index_by_feature_index))
+ {
+ switch (address_family)
+ {
+ case VNET_ADL_IP4:
+ {
+ static char *start_nodes[] = { "adl-input" };
+ static char *feature_nodes[] = {
+ [IP4_RX_ADL_ALLOWLIST] = "ip4-adl-allowlist",
+ [IP4_RX_ADL_INPUT] = "ip4-input",
+ };
+
+ vnet_config_init (vm, &acm->config_main,
+ start_nodes, ARRAY_LEN (start_nodes),
+ feature_nodes, ARRAY_LEN (feature_nodes));
+ }
+ break;
+ case VNET_ADL_IP6:
+ {
+ static char *start_nodes[] = { "adl-input" };
+ static char *feature_nodes[] = {
+ [IP6_RX_ADL_ALLOWLIST] = "ip6-adl-allowlist",
+ [IP6_RX_ADL_INPUT] = "ip6-input",
+ };
+ vnet_config_init (vm, &acm->config_main,
+ start_nodes, ARRAY_LEN (start_nodes),
+ feature_nodes, ARRAY_LEN (feature_nodes));
+ }
+ break;
+
+ case VNET_ADL_DEFAULT:
+ {
+ static char *start_nodes[] = { "adl-input" };
+ static char *feature_nodes[] = {
+ [DEFAULT_RX_ADL_ALLOWLIST] = "default-adl-allowlist",
+ [DEFAULT_RX_ADL_INPUT] = "ethernet-input",
+ };
+ vnet_config_init (vm, &acm->config_main,
+ start_nodes, ARRAY_LEN (start_nodes),
+ feature_nodes, ARRAY_LEN (feature_nodes));
+ }
+ break;
+
+ default:
+ clib_warning ("bug");
+ break;
+ }
+ }
+ vec_validate_init_empty (acm->config_index_by_sw_if_index, sw_if_index,
+ ~0);
+
+ ci = acm->config_index_by_sw_if_index[sw_if_index];
+
+ /* Create a sensible initial config: send pkts to xxx-input */
+ if (address_family == VNET_ADL_IP4)
+ default_next = IP4_RX_ADL_INPUT;
+ else if (address_family == VNET_ADL_IP6)
+ default_next = IP6_RX_ADL_INPUT;
+ else
+ default_next = DEFAULT_RX_ADL_INPUT;
+
+ if (is_add)
+ ci = vnet_config_add_feature (vm, &acm->config_main,
+ ci, default_next, data, sizeof (*data));
+ else
+ {
+ /* If the feature was actually configured */
+ if (ci != ~0)
+ {
+ ci = vnet_config_del_feature (vm, &acm->config_main,
+ ci, default_next, data,
+ sizeof (*data));
+ }
+ }
+
+ acm->config_index_by_sw_if_index[sw_if_index] = ci;
+ }
+ return 0;
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (adl_sw_interface_add_del);
+
+static clib_error_t *
+adl_init (vlib_main_t * vm)
+{
+ adl_main_t *cm = &adl_main;
+
+ cm->vlib_main = vm;
+ cm->vnet_main = vnet_get_main ();
+
+ /*
+ * Setup the packet generator so we can inject ethernet
+ * frames into this node
+ */
+ ethernet_setup_node (vm, adl_input_node.index);
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_INIT_FUNCTION (adl_init) =
+{
+ .runs_after = VLIB_INITS ("ip4_allowlist_init", "ip6_allowlist_init"),
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VNET_FEATURE_INIT (adl, static) =
+{
+ .arc_name = "device-input",
+ .node_name = "adl-input",
+ .runs_before = VNET_FEATURES ("ethernet-input"),
+};
+/* *INDENT-ON */
+
+int adl_interface_enable_disable (u32 sw_if_index, int enable_disable)
+{
+ /*
+ * Redirect pkts from the driver to the adl node.
+ */
+ vnet_feature_enable_disable ("device-input", "adl-input",
+ sw_if_index, enable_disable, 0, 0);
+ return 0;
+}
+
+static clib_error_t *
+adl_enable_disable_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ adl_main_t * cm = &adl_main;
+ u32 sw_if_index = ~0;
+ int enable_disable = 1;
+
+ int rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (input, "disable"))
+ enable_disable = 0;
+ else if (unformat (input, "%U", unformat_vnet_sw_interface,
+ cm->vnet_main, &sw_if_index))
+ ;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "Please specify an interface...");
+
+ rv = adl_interface_enable_disable (sw_if_index, enable_disable);
+
+ switch(rv) {
+ case 0:
+ break;
+
+ case VNET_API_ERROR_INVALID_SW_IF_INDEX:
+ return clib_error_return
+ (0, "Invalid interface, only works on physical ports");
+ break;
+
+ case VNET_API_ERROR_UNIMPLEMENTED:
+ return clib_error_return (0, "Device driver doesn't support redirection");
+ break;
+
+ default:
+ return clib_error_return (0, "adl_interface_enable_disable returned %d",
+ rv);
+ }
+ return 0;
+}
+
+VLIB_CLI_COMMAND (adl_interface_command, static) = {
+ .path = "adl interface",
+ .short_help =
+ "adl interface <interface-name> [disable]",
+ .function = adl_enable_disable_command_fn,
+};
+
+
+int adl_allowlist_enable_disable (adl_allowlist_enable_disable_args_t *a)
+{
+ adl_main_t * cm = &adl_main;
+ vlib_main_t * vm = cm->vlib_main;
+ ip4_main_t * im4 = &ip4_main;
+ ip6_main_t * im6 = &ip6_main;
+ int address_family;
+ int is_add;
+ adl_config_main_t * acm;
+ u32 next_to_add_del = 0;
+ uword * p;
+ u32 fib_index = 0;
+ u32 ci;
+ adl_config_data_t _data, *data=&_data;
+
+ /*
+ * Enable / disable allowlist processing on the specified interface
+ */
+
+ for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
+ address_family++)
+ {
+ acm = &cm->adl_config_mains[address_family];
+
+ switch(address_family)
+ {
+ case VNET_ADL_IP4:
+ is_add = (a->ip4 != 0);
+ next_to_add_del = IP4_RX_ADL_ALLOWLIST;
+ /* configured opaque data must match, or no supper */
+ p = hash_get (im4->fib_index_by_table_id, a->fib_id);
+ if (p)
+ fib_index = p[0];
+ else
+ {
+ if (is_add)
+ return VNET_API_ERROR_NO_SUCH_FIB;
+ else
+ continue;
+ }
+ break;
+
+ case VNET_ADL_IP6:
+ is_add = (a->ip6 != 0);
+ next_to_add_del = IP6_RX_ADL_ALLOWLIST;
+ p = hash_get (im6->fib_index_by_table_id, a->fib_id);
+ if (p)
+ fib_index = p[0];
+ else
+ {
+ if (is_add)
+ return VNET_API_ERROR_NO_SUCH_FIB;
+ else
+ continue;
+ }
+ break;
+
+ case VNET_ADL_DEFAULT:
+ is_add = (a->default_adl != 0);
+ next_to_add_del = DEFAULT_RX_ADL_ALLOWLIST;
+ break;
+
+ default:
+ clib_warning ("BUG");
+ }
+
+ ci = acm->config_index_by_sw_if_index[a->sw_if_index];
+ data->fib_index = fib_index;
+
+ if (is_add)
+ ci = vnet_config_add_feature (vm, &acm->config_main,
+ ci,
+ next_to_add_del,
+ data, sizeof (*data));
+ else
+ {
+ /* If the feature was actually configured... */
+ if (ci != ~0)
+ {
+ /* delete it */
+ ci = vnet_config_del_feature (vm, &acm->config_main,
+ ci,
+ next_to_add_del,
+ data, sizeof (*data));
+ }
+ }
+
+ acm->config_index_by_sw_if_index[a->sw_if_index] = ci;
+ }
+ return 0;
+}
+
+static clib_error_t *
+adl_allowlist_enable_disable_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ adl_main_t * cm = &adl_main;
+ u32 sw_if_index = ~0;
+ u8 ip4 = 0;
+ u8 ip6 = 0;
+ u8 default_adl = 0;
+ u32 fib_id = 0;
+ int rv;
+ adl_allowlist_enable_disable_args_t _a, * a = &_a;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (input, "ip4"))
+ ip4 = 1;
+ else if (unformat (input, "ip6"))
+ ip6 = 1;
+ else if (unformat (input, "default"))
+ default_adl = 1;
+ else if (unformat (input, "%U", unformat_vnet_sw_interface,
+ cm->vnet_main, &sw_if_index))
+ ;
+ else if (unformat (input, "fib-id %d", &fib_id))
+ ;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "Please specify an interface...");
+
+ a->sw_if_index = sw_if_index;
+ a->ip4 = ip4;
+ a->ip6 = ip6;
+ a->default_adl = default_adl;
+ a->fib_id = fib_id;
+
+ rv = adl_allowlist_enable_disable (a);
+
+ switch(rv) {
+ case 0:
+ break;
+
+ case VNET_API_ERROR_INVALID_SW_IF_INDEX:
+ return clib_error_return
+ (0, "Invalid interface, only works on physical ports");
+ break;
+
+ case VNET_API_ERROR_NO_SUCH_FIB:
+ return clib_error_return
+ (0, "Invalid fib");
+ break;
+
+ case VNET_API_ERROR_UNIMPLEMENTED:
+ return clib_error_return (0, "Device driver doesn't support redirection");
+ break;
+
+ default:
+ return clib_error_return (0, "adl_allowlist_enable_disable returned %d",
+ rv);
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (adl_allowlist_command, static) =
+{
+ .path = "adl allowlist",
+ .short_help =
+ "adl allowlist <interface-name> [ip4][ip6][default][fib-id <NN>][disable]",
+ .function = adl_allowlist_enable_disable_command_fn,
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () =
+{
+ .version = VPP_BUILD_VER,
+ .description = "Allow/deny list plugin",
+};
+/* *INDENT-ON* */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */