diff --git a/src/bld_cscope.sh b/src/bld_cscope.sh new file mode 100755 index 000000000000..39f03c3bb154 --- /dev/null +++ b/src/bld_cscope.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +echo -e "\033[36m Building Cscope ...\033[0m" +uname=`uname -s` +if [ x$uname == xLinux ] +then + find -type f -and -regex '.*/.*\.\(c\|cpp\|cc\|h\|hpp\|p4\|s\|asm\|py\|proto\|spec\|go\)$' > cscope.files + find ../platform/ -type f -and -regex '.*/.*\.\(c\|cpp\|cc\|h\|hpp\|p4\|s\|asm\|py\|proto\|spec\|go\)$' >> cscope.files +elif [ x$uname == xDarwin ] +then + find . -name '*.c' 2> /dev/null > cscope.files + find . -name '*.cpp' 2> /dev/null >> cscope.files + find . -name '*.cc' 2> /dev/null >> cscope.files + find . -name '*.hpp' 2> /dev/null >> cscope.files + find . -name '*.p4' 2> /dev/null >> cscope.files + find . -name '*.s' 2> /dev/null >> cscope.files + find . -name '*.asm' 2> /dev/null >> cscope.files + find . -name '*.py' 2> /dev/null >> cscope.files + find . -name '*.proto' 2> /dev/null >> cscope.files + find . -name '*.spec' 2> /dev/null >> cscope.files + find . -name '*.go' 2> /dev/null >> cscope.files +fi + +cscope -b -q + + +echo -e "\033[36m Done !! \033[0m" diff --git a/src/plugins/udps/CMakeLists.txt b/src/plugins/udps/CMakeLists.txt new file mode 100644 index 000000000000..a85d88eee618 --- /dev/null +++ b/src/plugins/udps/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (c) 2018 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(udps + SOURCES + udps_node.c + udps_cli.c + udps_db.c +) diff --git a/src/plugins/udps/udps.h b/src/plugins/udps/udps.h new file mode 100644 index 000000000000..c0004dc723b5 --- /dev/null +++ b/src/plugins/udps/udps.h @@ -0,0 +1,138 @@ +#ifndef __UDPS_H__ +#define __UDPS_H__ + +#define UDPS_NO_PORT (~0) +#define UDPS_NO_ACTION (NULL) +#define UDPS_INVALID_RULE (255) +#define UDPS_INVALID_POLICY_ID (~0) + +enum udps_rewrite_oper_e { + UDPS_REWRITE_UNUSED = 0, + UDPS_REWRITE_INSERT, + UDPS_REWRITE_REPLACE, + UDPS_REWRITE_REMOVE +}; + +enum udps_match_oper_e { + UDPS_MATCH_UNUSED = 0, + UDPS_MATCH_PKT, +}; + +typedef struct udps_rewrite_s { + u8 oper; + u16 offset; + u8 *value; + u8 len; +} udps_rewrite_t; + +typedef struct udps_rule_action_s { + u8 *name; + udps_rewrite_t *rewrite; + u32 out_port; +} udps_rule_action_t; + +typedef struct udps_match_pkt_s { + u16 offset; + u8 *value; +} udps_match_pkt_t; + +typedef struct udps_rule_entry_s { + u8 rule_id; + udps_match_pkt_t *match_pkt; + u32 act_id; +} udps_rule_entry_t; + +typedef struct udps_policy_entry_s { + u8 *name; + udps_rule_entry_t *rules; +} udps_policy_entry_t; + +typedef struct udps_main_s { + u32 *ing_policy_by_sw_if_index; + u32 *egr_policy_by_sw_if_index; + udps_policy_entry_t *policy_db; + udps_rule_action_t *action_db; + uword *action_by_name; + uword *policy_by_name; +} udps_main_t; + +/* Add a rule action. + Creates action if not present. + If already present updates the existing one. + name, oper are mandatory. + oper determines which of offset, value, len are set. +*/ +void udps_db_rule_action_add(u8 *name, u8 oper, u16 offset, u8 *value, u8 len, u32 out_port); + +/* Delete a rule action. + Deletes action if not used by a policy. + If used, returns false. +*/ +bool udps_db_rule_action_del(u8 *name); + +/* Get a rule action. + If present, rule action is returned in ra. + Otherwise, returns false. +*/ +bool udps_db_rule_action_get(u8 *name, udps_rule_action_t **ra); + +/* Get a matching rule action for the packet. + If present, rule action is returned in ra. + Otherwise, returns false. +*/ +bool udps_db_rule_match(u32 sw_if_index, u8 is_rx, u8 *bytes, u16 len, udps_rule_action_t **ra); + +/* Add a rule entry. + Creates rule entry if not present. + If already present updates the existing one. + name, id, oper are mandatory. + oper determines if offset, value is valid. + If aname is not created yet, returns false. +*/ +bool udps_db_rule_entry_add(u8 *name, u8 id, u8 oper, u16 offset, u8 *value, u8 *aname); + +/* Get the rule entry count. +*/ +u8 udps_db_rule_entry_cnt(u8 *name); + +/* Get a rule entry. + If present, rule entry is returned in re. + Otherwise, returns false. +*/ +bool udps_db_rule_entry_get(u8 *name, u8 id, udps_rule_entry_t **re); + +/* Delete a policy. + Deletes policy if not used by an interface. + If used, returns false. +*/ +bool udps_db_rule_policy_del(u8 *name); + +/* Applies policy on interface in the given direction. +*/ +void udps_db_policy_apply(u32 sw_if_index, u8 is_rx, u8 *name); + +/* Removes policy on interface in the given direction. +*/ +void udps_db_policy_remove(u32 sw_if_index, u8 is_rx); + +/* Applies policy on interface in the given direction. +*/ +void udps_node_policy_apply(u32 sw_if_index, u8 is_rx); + +/* Removes policy on interface in the given direction. +*/ +void udps_node_policy_remove(u32 sw_if_index, u8 is_rx); + +/* Get policy by name. + If present, policy entry is returned in pe. + Otherwise, returns false. +*/ +bool udps_db_rule_policy_get(u8 *name, udps_policy_entry_t **pe); + +/* Get policy on interface in the given direction. + If present, policy entry is returned in pe. + Otherwise, returns false. +*/ +bool udps_db_policy_get_by_sw_if_index(u32 sw_if_index, u8 is_rx, udps_policy_entry_t **pe); + +#endif /* __UDPS_H__ */ diff --git a/src/plugins/udps/udps_cli.c b/src/plugins/udps/udps_cli.c new file mode 100644 index 000000000000..380332db5b3c --- /dev/null +++ b/src/plugins/udps/udps_cli.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 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 "udps_includes.h" + +static clib_error_t * +udps_policy_action_set (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u8* action_name = 0; + u8* rewrite_str = 0; + u32 out_port = UDPS_NO_PORT; + clib_error_t *error = 0; + u32 offset_val = 0, len = 0; + enum udps_rewrite_oper_e oper = UDPS_REWRITE_UNUSED; + u8 offset_set = 0, name_set = 0, insert_set = 0, replace_set = 0, remove_set = 0, out_port_set = 0, rewrite_str_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %s", &action_name)) { + name_set = 1; + } else if (unformat(input, "offset %u", &offset_val)) { + offset_set = 1; + } else if (unformat(input, "insert")) { + insert_set = 1; + } else if (unformat(input, "replace")) { + replace_set = 1; + } else if (unformat(input, "rewrite_string %U", unformat_hex_string, &rewrite_str)) { + rewrite_str_set = 1; + } else if (unformat(input, "remove %u", &len)) { + remove_set = 1; + } else if (unformat(input, "out-port %U", unformat_vnet_sw_interface, vnm, &out_port)) { + out_port_set = 1; + } else { + vlib_cli_output(vm, "ERROR: Specify policy-action name " + " [offset [ [insert|replace] rewrite_string ]" + " | remove ] [out-port ]\n"); + return 0; + } + } + + if (!name_set || !offset_set) { + vlib_cli_output(vm, "ERROR: Invalid Command"); + return error; + } + + if (replace_set) { + oper = UDPS_REWRITE_REPLACE; + } else if (remove_set) { + oper = UDPS_REWRITE_REMOVE; + } else if (insert_set) { + oper = UDPS_REWRITE_INSERT; + } else { + oper = UDPS_REWRITE_UNUSED; + } + udps_db_rule_action_add(action_name, oper, offset_val, rewrite_str, len, out_port); + vlib_cli_output(vm, "Policy action added successfuly.\n"); + return error; +} + +/* + * This Commands configure policy-action for UDPS feature + * set udps policy-action [offset [ [insert|replace] ] | remove ] [out-port ] + * Notes: above command can be usede to add multiple rewrites, single port redirect to same policy action (identified by action-name). +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_udps_policy_action_command, static) = { + .path = "set udps policy-action", + .function = udps_policy_action_set, + .short_help = "set udps policy-action name " + "[offset [ [insert|replace] rewrite_string ] | [remove ]]" + " [out-port ]", +}; +/* *INDENT-ON* */ + +char* udps_oper_id_to_name(u8 oper) +{ + switch(oper) { + case UDPS_REWRITE_UNUSED: + return "UDPS_REWRITE_UNUSED"; + case UDPS_REWRITE_INSERT: + return "UDPS_REWRITE_INSERT"; + case UDPS_REWRITE_REPLACE: + return "UDPS_REWRITE_REPLACE"; + case UDPS_REWRITE_REMOVE: + return "UDPS_REWRITE_REMOVE"; + default: + return ""; + } + return ""; +} + +void +udps_dump_policy_action (vlib_main_t * vm, u8* action_name) +{ + udps_rule_action_t *ra; + char delimiter[65] = ""; + bool ret = udps_db_rule_action_get(action_name, &ra); + if (!ret) { + vlib_cli_output(vm, "No Policy Action found for given name = %s", action_name); + return; + } + vlib_cli_output(vm, "Policy Action"); + for (int i = 0; i < 65; i++) { + strcat(delimiter, "-"); + } + vlib_cli_output(vm, "%s\n", delimiter); + vlib_cli_output(vm,"%-40s : %s", "Policy Action name", ra->name); + vlib_cli_output(vm,"%-40s : %d", "Out-port", ra->out_port); + vlib_cli_output(vm,"%-40s : %s", "Oper", udps_oper_id_to_name(ra->rewrite->oper)); + vlib_cli_output(vm,"%-40s : %d", "Packet Offset", ra->rewrite->offset); + if (ra->rewrite->oper == UDPS_REWRITE_REMOVE) { + vlib_cli_output(vm,"%-40s : %d", "Rewrite Length", ra->rewrite->len); + } + vlib_cli_output(vm,"%-40s : %U", "Value", format_hex_bytes, ra->rewrite->value, vec_len(ra->rewrite->value)); +} + +static clib_error_t * +udps_policy_action_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u8* action_name = 0; + u8 name_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %s", &action_name)) { + name_set = 1; + } else { + vlib_cli_output(vm, "ERROR: Cli not in correct form\n"); + return 0; + } + } + + if (!name_set) { + vlib_cli_output(vm, "ERROR: Policy action name needed!"); + return error; + } + udps_dump_policy_action(vm, action_name); + return error; +} + +/* + * This Commands show policy-action for UDPS feature + * show udps policy-action +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_udps_policy_action_command, static) = { + .path = "show udps policy-action", + .function = udps_policy_action_show, + .short_help = "show udps policy-action name ", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +static clib_error_t * +udps_policy_action_delete (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u8* action_name = 0; + u8 name_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %s", &action_name)) { + name_set = 1; + } else { + vlib_cli_output(vm, "ERROR: Cli not in correct form\n"); + return 0; + } + } + + if (!name_set) { + vlib_cli_output(vm, "ERROR: Policy action name needed!"); + return error; + } + udps_db_rule_action_del(action_name); + vlib_cli_output(vm, "Policy action deleted successfully"); + return error; +} + +/* + * This Commands delete policy-action for UDPS feature + * delete udps policy-action +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (delete_udps_policy_action_command, static) = { + .path = "delete udps policy-action", + .function = udps_policy_action_delete, + .short_help = "delete udps policy-action ", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +static clib_error_t * +udps_policy_set (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u8* policy_name = 0, *action_name = 0; + u8* val_str = 0; + u32 offset_val = 0, id = 0; + u8 offset_set = 0, name_set = 0, action_set = 0, rule_id_set = 0, val_str_set = 0; + + enum udps_match_oper_e oper; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %s", &policy_name)) { + name_set = 1; + } else if(unformat(input, "rule %u", &id)) { + rule_id_set = 1; + } else if (unformat(input, "offset %u", &offset_val)) { + offset_set = 1; + } else if (unformat(input, "val %U", unformat_hex_string, &val_str)) { + val_str_set = 1; + } else if (unformat(input, "action %s", &action_name)) { + action_set = 1; + } else { + vlib_cli_output(vm, "ERROR: CLI not in proper form\n"); + return 0; + } + } + + if (!name_set || !rule_id_set) { + vlib_cli_output(vm, "ERROR: Invalid Command"); + return error; + } + + if (offset_set) { + oper = UDPS_MATCH_PKT; + } else { + oper = UDPS_MATCH_UNUSED; + } + + udps_db_rule_entry_add(policy_name, id, oper, offset_val, val_str, action_name); + vlib_cli_output(vm, "Policy Rule addedd successfully.\n"); + return error; +} + +/* + * This Commands configure policy for UDPS feature + * set udps policy rule [ offset val ] [ action ] + * Notes: above command can be usede to add multiples rules to a policy. Mulitiple matches in each rule are allowed. For now, single action in a rule. +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_udps_policy_command, static) = { + .path = "set udps policy", + .function = udps_policy_set, + .short_help = "set udps policy name rule [ offset val ] [ action ]", +}; +/* *INDENT-ON* */ + +void +udps_dump_policy_rule_by_rule_entry (vlib_main_t * vm, udps_rule_entry_t *re, char *delimiter) +{ + vlib_cli_output(vm,"%-40s : %u", "Rule Id", re->rule_id); + vlib_cli_output(vm,"%-40s : %u", "Action Id", re->act_id); + vlib_cli_output(vm, "%s\n", delimiter); + vlib_cli_output(vm, "%-40s | %s", "Packet Offset", "Value"); + for (int i = 0; imatch_pkt); i++) { + vlib_cli_output(vm,"%-40d | %U", re->match_pkt[i].offset, format_hex_bytes, re->match_pkt[i].value, vec_len(re->match_pkt[i].value)); + } + vlib_cli_output(vm, "%s\n", delimiter); +} + +void +udps_dump_policy_rule_by_policy_entry (vlib_main_t * vm, udps_policy_entry_t *pe, char *delimiter) +{ + vlib_cli_output(vm,"%-40s : %s", "Policy Name", pe->name); + vlib_cli_output(vm, "%s\n", delimiter); + + for (int i=0;i< vec_len(pe->rules); i++) { + if (pe->rules[i].rule_id == UDPS_INVALID_RULE){ + continue; + } + vlib_cli_output(vm, "\n"); + udps_dump_policy_rule_by_rule_entry(vm, &pe->rules[i], delimiter); + } +} + +void +udps_dump_policy_rule (vlib_main_t * vm, u8* policy_name) +{ + udps_policy_entry_t *pe; + char delimiter[65] = ""; + bool ret = udps_db_rule_policy_get(policy_name, &pe); + if (!ret) { + vlib_cli_output(vm, "No policy rule found for given name:%s", policy_name); + return; + } + for (int i = 0; i < 65; i++) { + strcat(delimiter, "-"); + } + udps_dump_policy_rule_by_policy_entry(vm, pe, delimiter); +} + +void +udps_dump_policy_rule_by_id (vlib_main_t * vm, u8* policy_name, u32 id) +{ + udps_rule_entry_t *re; + char delimiter[65] = ""; + bool ret = udps_db_rule_entry_get(policy_name, id, &re); + if (!ret) { + vlib_cli_output(vm, "No policy rule found for given name:%s and id:%d", policy_name, id); + return; + } + vlib_cli_output(vm,"%-40s : %s", "Policy name", policy_name); + for (int i = 0; i < 65; i++) { + strcat(delimiter, "-"); + } + vlib_cli_output(vm, "%s\n", delimiter); + udps_dump_policy_rule_by_rule_entry(vm, re, delimiter); +} + +static clib_error_t * +udps_policy_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u8* policy_name = 0; + u32 id = 0; + u8 name_set = 0, rule_id_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %s", &policy_name)) { + name_set = 1; + } else if(unformat(input, "rule %u", &id)) { + rule_id_set = 1; + } else { + vlib_cli_output(vm, "ERROR: CLI not in proper form\n"); + return 0; + } + } + + if (!name_set) { + vlib_cli_output(vm, "ERROR: Policy name"); + return error; + } + + if (rule_id_set) { + udps_dump_policy_rule_by_id(vm, policy_name, id); + } else { + udps_dump_policy_rule(vm, policy_name); + } + + return error; +} + +/* + * This Commands show policy for UDPS feature + * show udps policy +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_udps_policy_command, static) = { + .path = "show udps policy", + .function = udps_policy_show, + .short_help = "show udps policy name [rule ]", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +static clib_error_t * +udps_policy_delete (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u8* policy_name = 0; + u8 name_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %s", &policy_name)) { + name_set = 1; + } else { + vlib_cli_output(vm, "ERROR: CLI not in proper form\n"); + return 0; + } + } + + if (!name_set) { + vlib_cli_output(vm, "ERROR: Policy rule name required."); + return error; + } + udps_db_rule_policy_del(policy_name); + vlib_cli_output(vm, "Policy rule deleted successfully \n"); + return error; +} + +/* + * This Commands delete policy for UDPS feature + * delete udps policy +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (delete_udps_policy_command, static) = { + .path = "delete udps policy", + .function = udps_policy_delete, + .short_help = "delete udps policy ", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +static clib_error_t * +udps_policy_interface_set (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u32 if_name; + vnet_main_t *vnm = vnet_get_main (); + u8* policy_name = 0; + u8 rx_set = 0, tx_set = 0, policy_set = 0, name_set = 0; + + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %U", unformat_vnet_sw_interface, vnm, &if_name)) { + name_set = 1; + } else if(unformat(input, "direction")) { + if (unformat(input, "rx")) { + rx_set = 1; + } else if (unformat(input, "tx")) { + tx_set = 1; + } else { + vlib_cli_output(vm, "ERROR: Invalid direction\n"); + return 0; + } + } else if (unformat(input, "policy %s", &policy_name)) { + policy_set = 1; + } else { + vlib_cli_output(vm, "ERROR: CLI not in proper form\n"); + return 0; + } + } + + if (!name_set || !(rx_set || tx_set) || !policy_set ) { + vlib_cli_output(vm, "ERROR: Invalid Command"); + return error; + } + + udps_db_policy_apply(if_name, rx_set, policy_name); + udps_node_policy_apply(if_name, rx_set); + vlib_cli_output(vm, "Policy applied on interface successfully\n"); + return error; +} + +/* + * This Commands apply UDPS feature policy on interface + * set udps interface direction policy +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_udps_policy_interface_command, static) = { + .path = "set udps interface", + .function = udps_policy_interface_set, + .short_help = "set udps interface name direction policy ", +}; +/* *INDENT-ON* */ + +void +udps_dump_interface_policy (vlib_main_t * vm, u32 if_index, u8 is_rx) +{ + udps_policy_entry_t *pe; + char delimiter[65] = ""; + bool ret = udps_db_policy_get_by_sw_if_index(if_index, is_rx, &pe); + if (!ret) { + vlib_cli_output(vm, "No policy entry found for given if_index:%d and direction :%s", + if_index, is_rx?"RX":"TX"); + return; + } + vlib_cli_output(vm, "Interface Policy sw_if_index=%d Direction=%s", if_index, is_rx?"RX":"TX"); + for (int i = 0; i < 65; i++) { + strcat(delimiter, "-"); + } + vlib_cli_output(vm, "%s\n\n", delimiter); + udps_dump_policy_rule_by_policy_entry(vm, pe, delimiter); +} + +static clib_error_t * +udps_policy_interface_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + vnet_main_t *vnm = vnet_get_main (); + u32 if_name; + u8 name_set = 0; + u8 rx_set = 0, tx_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %U", unformat_vnet_sw_interface, vnm, &if_name)) { + name_set = 1; + } else if(unformat(input, "direction")) { + if (unformat(input, "rx")) { + rx_set = 1; + } else if (unformat(input, "tx")) { + tx_set = 1; + } else { + vlib_cli_output(vm, "ERROR: Invalid direction\n"); + return 0; + } + } else { + vlib_cli_output(vm, "ERROR: CLI not in proper form\n"); + return 0; + } + } + + if (!name_set || (!rx_set && !tx_set)) { + vlib_cli_output(vm, "Error: Interface name and direction required\n"); + return 0; + } + + udps_dump_interface_policy (vm, if_name, rx_set); + return error; +} + +/* + * This Commands show policy for UDPS feature on interface + * show udps interface +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_udps_policy_interface_command, static) = { + .path = "show udps interface", + .function = udps_policy_interface_show, + .short_help = "show udps interface name direction ", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +static clib_error_t * +udps_policy_interface_delete (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + vnet_main_t *vnm = vnet_get_main (); + u32 if_name; + u8 name_set = 0; + u8 rx_set = 0, tx_set = 0; + while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "name %U", unformat_vnet_sw_interface, vnm, &if_name)) { + name_set = 1; + } else if(unformat(input, "direction")) { + if (unformat(input, "rx")) { + rx_set = 1; + } else if (unformat(input, "tx")) { + tx_set = 1; + } else { + vlib_cli_output(vm, "ERROR: Invalid direction\n"); + return 0; + } + } else { + vlib_cli_output(vm, "ERROR: CLI not in proper form\n"); + return 0; + } + } + + if (!name_set || (!rx_set && !tx_set)) { + vlib_cli_output(vm, "Error: Interface name and direction required\n"); + return 0; + } + udps_db_policy_remove(if_name, rx_set); + vlib_cli_output(vm, "Interface Policy Deleted Successfully\n"); + return error; +} + +/* + * This Commands delete policy for UDPS feature on an interface + * delete udps interface direction +*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (delete_udps_policy_interface_command, static) = { + .path = "delete udps interface", + .function = udps_policy_interface_delete, + .short_help = "delete udps interface direction ", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + + diff --git a/src/plugins/udps/udps_db.c b/src/plugins/udps/udps_db.c new file mode 100644 index 000000000000..bb14a9be405f --- /dev/null +++ b/src/plugins/udps/udps_db.c @@ -0,0 +1,328 @@ +#include "udps_includes.h" + +udps_main_t udps_main; + +void +udps_db_rule_action_add(u8 *name, u8 oper, u16 offset, u8 *value, u8 len, u32 out_port) +{ + udps_rewrite_t rw; + udps_rule_action_t *ra; + u32 act_id; + bool ret; + + ret = udps_db_rule_action_get(name, &ra); + if (false == ret) { + pool_get(udps_main.action_db, ra); + act_id = ra - udps_main.action_db; + ra->name = format(0, "%s%c", name, 0); + ra->rewrite = NULL; + ra->out_port = UDPS_NO_PORT; + } + rw.oper = oper; + switch(oper) { + case UDPS_REWRITE_INSERT: + case UDPS_REWRITE_REPLACE: + rw.offset = offset; + rw.value = vec_dup(value); + vec_add1(ra->rewrite, rw); + break; + case UDPS_REWRITE_REMOVE: + rw.offset = offset; + rw.len = len; + vec_add1(ra->rewrite, rw); + break; + } + if (UDPS_NO_PORT != out_port) { + ra->out_port = out_port; + } + if (false == ret){ + hash_set_mem(udps_main.action_by_name, ra->name, act_id); + } +} + +bool +udps_db_rule_action_del(u8 *name) +{ + udps_rewrite_t rw; + udps_rule_action_t *ra; + bool ret; + + ret = udps_db_rule_action_get(name, &ra); + if (false == ret) { + return true; + } + hash_unset_mem(udps_main.action_by_name, ra->name); + for (int i = 0; i < vec_len(ra->rewrite); i++) { + rw = ra->rewrite[i]; + switch(rw.oper) { + case UDPS_REWRITE_INSERT: + case UDPS_REWRITE_REPLACE: + vec_free(rw.value); + break; + } + } + vec_free(ra->rewrite); + vec_free(ra->name); + pool_put(udps_main.action_db, ra); + + return true; +} + +bool +udps_db_rule_action_get(u8 *name, udps_rule_action_t **ra) +{ + uword *p; + u32 act_id; + + p = hash_get_mem(udps_main.action_by_name, name); + if (!p) { + return false; + } + act_id = p[0]; + *ra = pool_elt_at_index(udps_main.action_db, act_id); + return true; +} + +bool +udps_db_rule_match_pkt(u8 *bytes, u16 len, udps_match_pkt_t *mp) +{ + u32 mpl = mp->offset + vec_len(mp->value); + bool ret = true; + + if (mpl > len) { + return false; + } + + for (int i = mp->offset, j = 0; i < mpl; i++) { + if (bytes[i] != mp->value[j++]) { + ret = false; + break; + } + } + return ret; +} + +bool +udps_db_rule_item_match(u8 *bytes, u16 len, udps_rule_entry_t *re) +{ + bool ret; + + for (int i = 0; i < vec_len(re->match_pkt); i++) { + ret = udps_db_rule_match_pkt(bytes, len, &re->match_pkt[i]); + if (false == ret) { + return false; + } + } + return true; +} + + +bool +udps_db_rule_match(u32 sw_if_index, u8 is_rx, u8 *bytes, u16 len, udps_rule_action_t **ra) +{ + udps_policy_entry_t *pe; + u32 i; + bool ret; + + ret = udps_db_policy_get_by_sw_if_index(sw_if_index, is_rx, &pe); + if (false == ret) { + return false; + } + ret = false; + for (i = 0; i < vec_len(pe->rules); i++) { + ret = udps_db_rule_item_match(bytes, len, &pe->rules[i]); + if (true == ret) { + break; + } + } + if (false == ret) { + return false; + } + *ra = pool_elt_at_index(udps_main.action_db, pe->rules[i].act_id); + return true; +} + +bool +udps_db_rule_entry_add(u8 *name, u8 id, u8 oper, u16 offset, u8 *value, u8 *aname) +{ + udps_rule_entry_t ir = {UDPS_INVALID_RULE}; + udps_match_pkt_t mp; + udps_rule_action_t *ra; + udps_policy_entry_t *pe; + u32 policy_id; + u32 act_id; + bool ret; + + if (aname) { + ret = udps_db_rule_action_get(aname, &ra); + if (false == ret) { + return false; + } + act_id = ra - udps_main.action_db; + } + + ret = udps_db_rule_policy_get(name, &pe); + if (false == ret) { + pool_get(udps_main.policy_db, pe); + policy_id = pe - udps_main.policy_db; + pe->name = format(0, "%s%c", name, 0); + pe->rules = NULL; + } + vec_validate_init_empty(pe->rules, id, ir); + pe->rules[id].rule_id = id; + switch(oper) { + case UDPS_MATCH_PKT: + mp.offset = offset; + mp.value = vec_dup(value); + vec_add1(pe->rules[id].match_pkt, mp); + break; + } + if (aname) { + pe->rules[id].act_id = act_id; + } + if (false == ret){ + hash_set_mem(udps_main.policy_by_name, pe->name, policy_id); + } + return true; +} + +u8 +udps_db_rule_entry_cnt(u8 *name) +{ + udps_policy_entry_t *pe; + bool ret; + + ret = udps_db_rule_policy_get(name, &pe); + if (false == ret) { + return 0; + } + return vec_len(pe->rules); +} + +bool +udps_db_rule_entry_get(u8 *name, u8 id, udps_rule_entry_t **re) +{ + udps_policy_entry_t *pe; + bool ret; + + ret = udps_db_rule_policy_get(name, &pe); + if (false == ret) { + return false; + } + if (id >= vec_len(pe->rules)) { + return false; + } + if (pe->rules[id].rule_id == UDPS_INVALID_RULE) { + return false; + } + *re = &pe->rules[id]; + return true; +} + +bool +udps_db_rule_policy_del(u8 *name) +{ + udps_policy_entry_t *pe; + bool ret; + + ret = udps_db_rule_policy_get(name, &pe); + if (false == ret) { + return false; + } + hash_unset_mem(udps_main.policy_by_name, pe->name); + for (int i = 0; i < vec_len(pe->rules); i++) { + for (int j = 0; j < vec_len(pe->rules[i].match_pkt); j++) { + vec_free(pe->rules[i].match_pkt[j].value); + } + vec_free(pe->rules[i].match_pkt); + } + vec_free(pe->rules); + vec_free(pe->name); + pool_put(udps_main.policy_db, pe); + + return true; +} + +bool +udps_db_rule_policy_get(u8 *name, udps_policy_entry_t **pe) +{ + uword *p; + u32 policy_id; + + p = hash_get_mem(udps_main.policy_by_name, name); + if (!p) { + return false; + } + policy_id = p[0]; + *pe = pool_elt_at_index(udps_main.policy_db, policy_id); + return true; +} + + +void +udps_db_policy_apply(u32 sw_if_index, u8 is_rx, u8 *name) +{ + uword *p; + u32 policy_id; + + p = hash_get_mem(udps_main.policy_by_name, name); + if (!p) { + return; + } + policy_id = p[0]; + + if (is_rx) { + vec_validate_init_empty(udps_main.ing_policy_by_sw_if_index, + sw_if_index, UDPS_INVALID_POLICY_ID); + udps_main.ing_policy_by_sw_if_index[sw_if_index] = policy_id; + } else { + vec_validate_init_empty(udps_main.egr_policy_by_sw_if_index, + sw_if_index, UDPS_INVALID_POLICY_ID); + udps_main.egr_policy_by_sw_if_index[sw_if_index] = policy_id; + } +} + +void +udps_db_policy_remove(u32 sw_if_index, u8 is_rx) +{ + if (is_rx) { + vec_validate_init_empty(udps_main.ing_policy_by_sw_if_index, + sw_if_index, UDPS_INVALID_POLICY_ID); + udps_main.ing_policy_by_sw_if_index[sw_if_index] = UDPS_INVALID_POLICY_ID; + } else { + vec_validate_init_empty(udps_main.egr_policy_by_sw_if_index, + sw_if_index, UDPS_INVALID_POLICY_ID); + udps_main.egr_policy_by_sw_if_index[sw_if_index] = UDPS_INVALID_POLICY_ID; + } +} + +bool +udps_db_policy_get_by_sw_if_index(u32 sw_if_index, u8 is_rx, udps_policy_entry_t **pe) +{ + int policy_id; + + if (is_rx) { + vec_validate_init_empty(udps_main.ing_policy_by_sw_if_index, + sw_if_index, UDPS_INVALID_POLICY_ID); + policy_id = udps_main.ing_policy_by_sw_if_index[sw_if_index]; + } else { + vec_validate_init_empty(udps_main.egr_policy_by_sw_if_index, + sw_if_index, UDPS_INVALID_POLICY_ID); + policy_id = udps_main.egr_policy_by_sw_if_index[sw_if_index]; + } + if (UDPS_INVALID_POLICY_ID == policy_id) { + return false; + } + *pe = pool_elt_at_index(udps_main.policy_db, policy_id); + return true; +} + +static clib_error_t* +udps_db_init (vlib_main_t *vm) +{ + udps_main.action_by_name = hash_create_string(0, sizeof(uword)); + udps_main.policy_by_name = hash_create_string(0, sizeof(uword)); + return 0; +} + +VLIB_INIT_FUNCTION (udps_db_init); diff --git a/src/plugins/udps/udps_includes.h b/src/plugins/udps/udps_includes.h new file mode 100644 index 000000000000..525a1085fa35 --- /dev/null +++ b/src/plugins/udps/udps_includes.h @@ -0,0 +1,22 @@ +#ifndef __UDPS_INCLUDES_H__ +#define __UDPS_INCLUDES_H__ + +/** Core VPP includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* udps includes */ +#include "udps.h" + +#endif /* __UDPS_INCLUDES_H__ */ diff --git a/src/plugins/udps/udps_node.c b/src/plugins/udps/udps_node.c new file mode 100644 index 000000000000..9bb97445db2f --- /dev/null +++ b/src/plugins/udps/udps_node.c @@ -0,0 +1,219 @@ +#include "udps_includes.h" + +#define foreach_udps_rx_error \ + _(UDPS_RX, "UDPS outgoing packets") \ + _(RULE_MATCHED, "Rule matched on intf") \ + _(RULE_ACTION_FOUND, "Rule action found") \ + _(VALID_OUT_PORT, "Out port rewritten") \ + _(DROP, "UDPS drop pkt") + +typedef enum +{ +#define _(sym,str) UDPS_RX_ERROR_##sym, + foreach_udps_rx_error +#undef _ + UDPS_RX_N_ERROR, +} udps_rx_error_t; + +static char *udps_rx_error_strings[] = { +#define _(sym,string) string, + foreach_udps_rx_error +#undef _ +}; + +void +udps_node_policy_apply(u32 sw_if_index, u8 is_rx) +{ + if (is_rx) { + vnet_feature_enable_disable("device-input", + "udps-rx-node", + sw_if_index, + 1, 0, 0); + } else { + vnet_feature_enable_disable("interface-output", + "udps-tx-node", + sw_if_index, + 1, 0, 0); + } +} + +void +udps_node_policy_remove(u32 sw_if_index, u8 is_rx) +{ + if (is_rx) { + vnet_feature_enable_disable("device-input", + "udps-rx-node", + sw_if_index, + 0, 0, 0); + } else { + vnet_feature_enable_disable("interface-output", + "udps-tx-node", + sw_if_index, + 0, 0, 0); + } +} +void +udps_apply_rule_action (vlib_main_t *vm, + vlib_buffer_t * b, + udps_rule_action_t *ra, + bool is_rx) +{ + int offset, len; + u8 *write_ptr; + /* rewrite the out_port and be done with this */ + if (ra->out_port != UDPS_NO_PORT) { + vnet_buffer (b)->sw_if_index[VLIB_TX] = ra->out_port; + } + + /* loop through all the rewrite actions and apply them one by one */ + for (int i = 0; i < vec_len(ra->rewrite); i++) { + switch(ra->rewrite[i].oper) { + case UDPS_REWRITE_INSERT: + offset = ra->rewrite[i].offset; + len = vec_len(ra->rewrite[i].value); + vlib_buffer_advance(b, offset); + vlib_buffer_move(vm, b, (len + offset)); + /* alter pkt len and rewind current_data*/ + b->current_length += len; + b->current_data -= len; + write_ptr = vlib_buffer_get_current (b); + clib_memcpy_fast (write_ptr, (u8 *)ra->rewrite[i].value, len); + /*rewind to start of l2 header again*/ + vlib_buffer_advance(b, -offset); + break; + case UDPS_REWRITE_REPLACE: + offset = ra->rewrite[i].offset; + len = vec_len(ra->rewrite[i].value); + vlib_buffer_advance(b, offset); + write_ptr = vlib_buffer_get_current (b); + clib_memcpy_fast (write_ptr, (u8 *)ra->rewrite[i].value, len); + /*rewind to start of l2 header again*/ + vlib_buffer_advance(b, -offset); + break; + case UDPS_REWRITE_REMOVE: + offset = ra->rewrite[i].offset; + len = ra->rewrite[i].len; + vlib_buffer_advance(b, len+offset); + vlib_buffer_move(vm, b, offset); + /*rewind to start of l2 header again*/ + vlib_buffer_advance(b, -offset); + break; + default: + break; + } + } + + return; +} +VLIB_NODE_FN (udps_rx_node) (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 counter[UDPS_RX_N_ERROR] = {0}; + u32 n_left_from, *from, *to_next; + vnet_device_input_next_t next_index; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + 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 > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + u8 *eth; + udps_rule_action_t *ra = NULL; + + /* 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); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + /* Determine the next node */ + //next0 = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT; // is this correct ?? + next0 = 0; + + /* Do the business logic */ + counter[UDPS_RX_ERROR_UDPS_RX]++; + + eth = (u8 *)vlib_buffer_get_current (b0); + if (udps_db_rule_match(sw_if_index0, true, eth, + vlib_buffer_length_in_chain(vm, b0),&ra)) { + counter[UDPS_RX_ERROR_RULE_MATCHED]++; + if (ra) { + counter[UDPS_RX_ERROR_RULE_ACTION_FOUND]++; + /* apply Rule action on b(0) */ + udps_apply_rule_action(vm, b0, ra, true); + if (ra->out_port != UDPS_NO_PORT) { + counter[UDPS_RX_ERROR_VALID_OUT_PORT]++; + next0 = 1; + } + } + } + + /* 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); + } + + +#define _(n, s) \ +{ \ + if (counter[UDPS_RX_ERROR_##n]) { \ + vlib_node_increment_counter(vm, node->node_index, \ + UDPS_RX_ERROR_##n, \ + counter[UDPS_RX_ERROR_##n]); \ + } \ +} + foreach_udps_rx_error +#undef _ + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (udps_rx_node) = +{ + .name = "udps-rx-node", + .vector_size = sizeof (u32), + .format_trace = NULL, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_next_nodes = 2, + .next_nodes = { [0] = "ethernet-input", + [1] = "interface-output" + }, + .n_errors = ARRAY_LEN(udps_rx_error_strings), + .error_strings = udps_rx_error_strings, +}; + +VNET_FEATURE_INIT (udps_rx_node, static) = +{ + .arc_name = "device-input", + .node_name = "udps-rx-node", + .runs_before = VNET_FEATURES ("ethernet-input"), +}; + +VLIB_PLUGIN_REGISTER () = +{ + .version = VPP_BUILD_VER, + .description = "user defined packet steer plugin registration", +}; +/* *INDENT-ON* */