aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/cop/cop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/cop/cop.c')
-rw-r--r--src/vnet/cop/cop.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/src/vnet/cop/cop.c b/src/vnet/cop/cop.c
new file mode 100644
index 00000000000..465d6c97a2a
--- /dev/null
+++ b/src/vnet/cop/cop.c
@@ -0,0 +1,387 @@
+/*
+ * 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 <vnet/cop/cop.h>
+
+cop_main_t cop_main;
+
+static clib_error_t *
+cop_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
+{
+ cop_main_t * cm = &cop_main;
+ cop_config_data_t _data, *data = &_data;
+ vlib_main_t * vm = cm->vlib_main;
+ vnet_hw_interface_t * hi = vnet_get_sup_hw_interface (vnm, sw_if_index);;
+ cop_config_main_t * ccm;
+ int address_family;
+ u32 ci, default_next;
+
+ 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_COP_IP4; address_family < VNET_N_COPS;
+ address_family++)
+ {
+ ccm = &cm->cop_config_mains[address_family];
+
+ /*
+ * Once-only code to initialize the per-address-family
+ * cop feature subgraphs.
+ * Since the (single) start-node, cop-input, must be able
+ * to push pkts into three separate subgraphs, we
+ * use a unified cop_feature_type_t enumeration.
+ */
+
+ if (!(ccm->config_main.node_index_by_feature_index))
+ {
+ switch (address_family)
+ {
+ case VNET_COP_IP4:
+ {
+ static char * start_nodes[] = { "cop-input" };
+ static char * feature_nodes[] = {
+ [IP4_RX_COP_WHITELIST] = "ip4-cop-whitelist",
+ [IP4_RX_COP_INPUT] = "ip4-input",
+ };
+
+ vnet_config_init (vm, &ccm->config_main,
+ start_nodes, ARRAY_LEN(start_nodes),
+ feature_nodes, ARRAY_LEN(feature_nodes));
+ }
+ break;
+ case VNET_COP_IP6:
+ {
+ static char * start_nodes[] = { "cop-input" };
+ static char * feature_nodes[] = {
+ [IP6_RX_COP_WHITELIST] = "ip6-cop-whitelist",
+ [IP6_RX_COP_INPUT] = "ip6-input",
+ };
+ vnet_config_init (vm, &ccm->config_main,
+ start_nodes, ARRAY_LEN(start_nodes),
+ feature_nodes, ARRAY_LEN(feature_nodes));
+ }
+ break;
+
+ case VNET_COP_DEFAULT:
+ {
+ static char * start_nodes[] = { "cop-input" };
+ static char * feature_nodes[] = {
+ [DEFAULT_RX_COP_WHITELIST] = "default-cop-whitelist",
+ [DEFAULT_RX_COP_INPUT] = "ethernet-input",
+ };
+ vnet_config_init (vm, &ccm->config_main,
+ start_nodes, ARRAY_LEN(start_nodes),
+ feature_nodes, ARRAY_LEN(feature_nodes));
+ }
+ break;
+
+ default:
+ clib_warning ("bug");
+ break;
+ }
+ }
+ vec_validate_init_empty (ccm->config_index_by_sw_if_index, sw_if_index,
+ ~0);
+
+ ci = ccm->config_index_by_sw_if_index[sw_if_index];
+
+ /* Create a sensible initial config: send pkts to xxx-input */
+ if (address_family == VNET_COP_IP4)
+ default_next = IP4_RX_COP_INPUT;
+ else if (address_family == VNET_COP_IP6)
+ default_next = IP6_RX_COP_INPUT;
+ else
+ default_next = DEFAULT_RX_COP_INPUT;
+
+ if (is_add)
+ ci = vnet_config_add_feature (vm, &ccm->config_main,
+ ci,
+ default_next,
+ data, sizeof(*data));
+ else
+ ci = vnet_config_del_feature (vm, &ccm->config_main,
+ ci,
+ default_next,
+ data, sizeof(*data));
+
+ ccm->config_index_by_sw_if_index[sw_if_index] = ci;
+ }
+ return 0;
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (cop_sw_interface_add_del);
+
+static clib_error_t *
+cop_init (vlib_main_t *vm)
+{
+ cop_main_t * cm = &cop_main;
+ clib_error_t * error;
+
+ if ((error = vlib_call_init_function (vm, ip4_whitelist_init)))
+ return error;
+
+ if ((error = vlib_call_init_function (vm, ip6_whitelist_init)))
+ return error;
+
+ cm->vlib_main = vm;
+ cm->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cop_init);
+
+int cop_interface_enable_disable (u32 sw_if_index, int enable_disable)
+{
+ cop_main_t * cm = &cop_main;
+ vnet_sw_interface_t * sw;
+ int rv;
+ u32 node_index = enable_disable ? cop_input_node.index : ~0;
+
+ /* Not a physical port? */
+ sw = vnet_get_sw_interface (cm->vnet_main, sw_if_index);
+ if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
+ return VNET_API_ERROR_INVALID_SW_IF_INDEX;
+
+ /*
+ * Redirect pkts from the driver to the cop node.
+ * Returns VNET_API_ERROR_UNIMPLEMENTED if the h/w driver
+ * doesn't implement the API.
+ *
+ * Node_index = ~0 => shut off redirection
+ */
+ rv = vnet_hw_interface_rx_redirect_to_node (cm->vnet_main, sw_if_index,
+ node_index);
+ return rv;
+}
+
+static clib_error_t *
+cop_enable_disable_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ cop_main_t * cm = &cop_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 = cop_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, "cop_interface_enable_disable returned %d",
+ rv);
+ }
+ return 0;
+}
+
+VLIB_CLI_COMMAND (cop_interface_command, static) = {
+ .path = "cop interface",
+ .short_help =
+ "cop interface <interface-name> [disable]",
+ .function = cop_enable_disable_command_fn,
+};
+
+
+int cop_whitelist_enable_disable (cop_whitelist_enable_disable_args_t *a)
+{
+ cop_main_t * cm = &cop_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;
+ cop_config_main_t * ccm;
+ u32 next_to_add_del = 0;
+ uword * p;
+ u32 fib_index = 0;
+ u32 ci;
+ cop_config_data_t _data, *data=&_data;
+
+ /*
+ * Enable / disable whitelist processing on the specified interface
+ */
+
+ for (address_family = VNET_COP_IP4; address_family < VNET_N_COPS;
+ address_family++)
+ {
+ ccm = &cm->cop_config_mains[address_family];
+
+ switch(address_family)
+ {
+ case VNET_COP_IP4:
+ is_add = (a->ip4 != 0);
+ next_to_add_del = IP4_RX_COP_WHITELIST;
+ /* 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_COP_IP6:
+ is_add = (a->ip6 != 0);
+ next_to_add_del = IP6_RX_COP_WHITELIST;
+ 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_COP_DEFAULT:
+ is_add = (a->default_cop != 0);
+ next_to_add_del = DEFAULT_RX_COP_WHITELIST;
+ break;
+
+ default:
+ clib_warning ("BUG");
+ }
+
+ ci = ccm->config_index_by_sw_if_index[a->sw_if_index];
+ data->fib_index = fib_index;
+
+ if (is_add)
+ ci = vnet_config_add_feature (vm, &ccm->config_main,
+ ci,
+ next_to_add_del,
+ data, sizeof (*data));
+ else
+ ci = vnet_config_del_feature (vm, &ccm->config_main,
+ ci,
+ next_to_add_del,
+ data, sizeof (*data));
+
+ ccm->config_index_by_sw_if_index[a->sw_if_index] = ci;
+ }
+ return 0;
+}
+
+static clib_error_t *
+cop_whitelist_enable_disable_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ cop_main_t * cm = &cop_main;
+ u32 sw_if_index = ~0;
+ u8 ip4 = 0;
+ u8 ip6 = 0;
+ u8 default_cop = 0;
+ u32 fib_id = 0;
+ int rv;
+ cop_whitelist_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_cop = 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_cop = default_cop;
+ a->fib_id = fib_id;
+
+ rv = cop_whitelist_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, "cop_whitelist_enable_disable returned %d",
+ rv);
+ }
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (cop_whitelist_command, static) = {
+ .path = "cop whitelist",
+ .short_help =
+ "cop whitelist <interface-name> [ip4][ip6][default][fib-id <NN>][disable]",
+ .function = cop_whitelist_enable_disable_command_fn,
+};
+