From e15e5cfff7f164b892a45d8913d5e7cfe02e7032 Mon Sep 17 00:00:00 2001 From: chenpiaoping Date: Mon, 19 Oct 2020 20:33:52 +0800 Subject: [PATCH 1/4] Implementation of Security Group --- include/aca_security_group.h | 167 +++++++++ include/aca_security_group_manager.h | 41 +++ include/aca_security_group_ovs.h | 74 ++++ include/aca_sg_state_handler.h | 45 +++ src/CMakeLists.txt | 8 +- src/comm/aca_comm_mgr.cpp | 13 + src/ovs/aca_ovs_l2_programmer.cpp | 4 +- src/sg/aca_security_group.cpp | 295 ++++++++++++++++ src/sg/aca_security_group_manager.cpp | 220 ++++++++++++ src/sg/aca_security_group_mizar.cpp | 0 src/sg/aca_security_group_ovs.cpp | 330 ++++++++++++++++++ src/sg/aca_sg_state_handler.cpp | 248 +++++++++++++ test/aca-sg-test/.idea/.gitignore | 2 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + test/aca-sg-test/.idea/compiler.xml | 13 + test/aca-sg-test/.idea/encodings.xml | 6 + test/aca-sg-test/.idea/misc.xml | 14 + test/aca-sg-test/.idea/vcs.xml | 6 + test/aca-sg-test/aca-sg-test.iml | 2 + test/aca-sg-test/pom.xml | 24 ++ .../aca/securitygroup/SecurityGroupTest.java | 145 ++++++++ .../target/aca-sg-test-1.0-SNAPSHOT.jar | Bin 0 -> 4753 bytes .../aca/securitygroup/SecurityGroupTest.class | Bin 0 -> 13662 bytes .../target/maven-archiver/pom.properties | 5 + .../compile/default-compile/createdFiles.lst | 1 + .../compile/default-compile/inputFiles.lst | 1 + .../default-testCompile/inputFiles.lst | 0 27 files changed, 1666 insertions(+), 3 deletions(-) create mode 100644 include/aca_security_group.h create mode 100644 include/aca_security_group_manager.h create mode 100644 include/aca_security_group_ovs.h create mode 100644 include/aca_sg_state_handler.h create mode 100644 src/sg/aca_security_group.cpp create mode 100644 src/sg/aca_security_group_manager.cpp create mode 100644 src/sg/aca_security_group_mizar.cpp create mode 100644 src/sg/aca_security_group_ovs.cpp create mode 100644 src/sg/aca_sg_state_handler.cpp create mode 100644 test/aca-sg-test/.idea/.gitignore create mode 100644 test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml create mode 100644 test/aca-sg-test/.idea/compiler.xml create mode 100644 test/aca-sg-test/.idea/encodings.xml create mode 100644 test/aca-sg-test/.idea/misc.xml create mode 100644 test/aca-sg-test/.idea/vcs.xml create mode 100644 test/aca-sg-test/aca-sg-test.iml create mode 100644 test/aca-sg-test/pom.xml create mode 100644 test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java create mode 100644 test/aca-sg-test/target/aca-sg-test-1.0-SNAPSHOT.jar create mode 100644 test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class create mode 100644 test/aca-sg-test/target/maven-archiver/pom.properties create mode 100644 test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 test/aca-sg-test/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst diff --git a/include/aca_security_group.h b/include/aca_security_group.h new file mode 100644 index 00000000..fbffc174 --- /dev/null +++ b/include/aca_security_group.h @@ -0,0 +1,167 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// 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 ALCOR_CONTROL_AGENT_SECURITY_GROUP_H +#define ALCOR_CONTROL_AGENT_SECURITY_GROUP_H +#include +#include +#include +#include + +using namespace std; + +namespace aca_security_group +{ + +enum OperationType { + CREATE=1, + UPDATE, + DELETE, +}; + +enum Direction { + INGRESS=1, + EGRESS, +}; + +enum Ethertype { + IPV4=0x0800, + ARP=0x0806, + IPV6=0x86dd +}; + +enum Protocol { + TCP=6, + UDP=17, + ICMP=1 +}; + + +class Aca_Security_Group_Rule { +public: + static Aca_Security_Group_Rule &get_instance(); + void set_id(string id); + string get_id(void); + void set_name(string name); + string get_name(void); + void set_cookie(uint64_t cookie); + uint64_t get_cookie(void); + void set_direction(Direction direction); + Direction get_direction(void); + void set_ethertype(Ethertype ethertype); + Ethertype get_ethertype(void); + void set_protocol(Protocol protocol); + Protocol get_protocol(void); + uint32_t get_port_range_min(void); + void set_port_range_min(uint32_t port_range_min); + uint32_t get_port_range_max(void); + void set_port_range_max(uint32_t port_range_max); + string get_remote_ip_prefix(void); + void set_remote_ip_prefix(string remote_ip_prefix); + void set_remote_group_id(string remote_group_id); + string get_remote_group_id(void); + void set_operation_type(OperationType operation_type); + OperationType get_operation_type(void); + +private: + string id; + string name; + uint64_t cookie; + Direction direction; + Ethertype ethertype; + Protocol protocol; + uint32_t port_range_min; + uint32_t port_range_max; + string remote_ip_prefix; + string remote_group_id; + OperationType operation_type; +}; + +class Aca_Security_Group { +public: + void set_id(string id); + string get_id(void); + void set_name(string name); + string get_name(void); + void set_format_version(uint32_t format_version); + uint32_t get_format_version(void); + void set_revision_number(uint32_t revision_number); + uint32_t get_revision_number(void); + void set_vpc_id(string vpc_id); + string get_vpc_id(void); + void set_operation_type(OperationType operation_type); + OperationType get_operation_type(void); + void add_security_group_rule(Aca_Security_Group_Rule *sg_rule); + void update_security_group_rule(Aca_Security_Group_Rule *sg_rule); + void delete_security_group_rule(string sg_rule_id); + Aca_Security_Group_Rule* get_security_group_rule(string sg_rule_id); + map get_security_group_rules(); + +private: + string id; + string name; + uint32_t format_version; + uint32_t revision_number; + string vpc_id; + OperationType operation_type; + map rules; +}; + +class Aca_Port { +public: + void set_id(string id); + string get_id(void); + void set_name(string name); + string get_name(void); + void set_ofport(uint32_t ofport); + uint32_t get_ofport(void); + void set_format_version(uint32_t format_version); + uint32_t get_format_version(void); + void set_revision_number(uint32_t revision_number); + uint32_t get_revision_number(void); + void set_vpc_id(string vpc_id); + string get_vpc_id(void); + void set_mac_address(string mac_address); + string get_mac_address(void); + void add_fixed_ip(string fixed_ip); + void add_security_group_id(string security_group_id); + void delete_security_group_id(string security_group_id); + int get_security_group_id_num(void); + void add_allow_address_pair(string ip_address, string mac_address); + int allow_address_pairs_size(void); + vector> get_allow_address_pairs(void); + void add_security_group(Aca_Security_Group *security_group); + Aca_Security_Group *get_security_group(string sg_id); + +private: + string id; + string name; + uint32_t ofport; + uint32_t vni; + uint32_t format_version; + uint32_t revision_number; + string vpc_id; + string mac_address; + vector fixed_ips; + vector security_group_ids; + vector> allow_address_pairs; + map security_groups; +}; + +} + +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_H diff --git a/include/aca_security_group_manager.h b/include/aca_security_group_manager.h new file mode 100644 index 00000000..86acfc34 --- /dev/null +++ b/include/aca_security_group_manager.h @@ -0,0 +1,41 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// 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 ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H +#define ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H +#include "aca_security_group.h" + + +namespace aca_security_group { + +class Aca_Security_Group_Manager { +public: + static Aca_Security_Group_Manager &get_instance(); + int create_security_group_rule(Aca_Port &port_state, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int update_security_group_rule(Aca_Port &port_state, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int delete_security_group_rule(Aca_Port &port_state, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int create_security_group(Aca_Port &port_state, Aca_Security_Group &sg); + int update_security_group(Aca_Port &port_state, Aca_Security_Group &sg); + int delete_security_group(Aca_Port &port_state, Aca_Security_Group &sg); + +private: + map ports; + map security_groups; +}; + +} +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H \ No newline at end of file diff --git a/include/aca_security_group_ovs.h b/include/aca_security_group_ovs.h new file mode 100644 index 00000000..c9f2b932 --- /dev/null +++ b/include/aca_security_group_ovs.h @@ -0,0 +1,74 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// 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 ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H +#define ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H + +#include "aca_security_group.h" + + +namespace aca_security_group { + +#define TRANSIENT_TABLE 60 +#define BASE_EGRESS_TABLE 71 +#define RULES_EGRESS_TABLE 72 +#define ACCEPT_OR_INGRESS_TABLE 73 +#define BASE_INGRESS_TABLE 81 +#define RULES_INGRESS_TABLE 82 +#define ACCEPTED_EGRESS_TRAFFIC_TABLE 91 +#define DROPPED_TRAFFIC_TABLE 93 +#define ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE 94 + +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_IPV6 0x86dd + +#define PROTO_NUM_ICMP 1 +#define PROTO_NUM_TCP 6 +#define PROTO_NUM_UDP 17 + +#define REG_PORT 5 +#define REG_NET 6 + +#define BR_INT "br-int" +#define BR_TUN "br-tun" + +class Aca_Security_Group_Ovs { +public: + static Aca_Security_Group_Ovs &get_instance(); + void init_port(Aca_Port &aca_port); + int create_port_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule); + int update_port_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule); + int delete_port_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule); +private: + int get_vlan_by_segment_id(const int segment_id); + void init_port_egress_flows(Aca_Port &aca_port); + void init_port_ingress_flows(const Aca_Port &aca_port); + int get_flow_priority(Aca_Security_Group_Rule &aca_sg_rule, int conjunction); + int get_dl_type_by_ether_type(uint32_t ether_type); + string get_nw_proto_by_protocol(uint32_t protocol); + void build_flows_from_sg_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule, + bool has_actions, + vector &flows); +}; + +} +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H \ No newline at end of file diff --git a/include/aca_sg_state_handler.h b/include/aca_sg_state_handler.h new file mode 100644 index 00000000..8d73fdaf --- /dev/null +++ b/include/aca_sg_state_handler.h @@ -0,0 +1,45 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// 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 ALCOR_CONTROL_AGENT_ACA_SG_STATE_HANDLER_H +#define ALCOR_CONTROL_AGENT_ACA_SG_STATE_HANDLER_H +#include "aca_security_group.h" +#include "goalstateprovisioner.grpc.pb.h" + +namespace aca_security_group +{ +class Aca_Sg_State_Handler { +public: + static Aca_Sg_State_Handler &get_instance(); + int update_security_group_states(const alcor::schema::GoalState &goal_state, + alcor::schema::GoalStateOperationReply &reply); + +private: + // constructor and destructor marked as private so that noone can call it + // for the singleton implementation + Aca_Sg_State_Handler(); + ~Aca_Sg_State_Handler(); + Aca_Port * parse_port_state(const alcor::schema::PortState &port_state); + void parse_security_group_states(const alcor::schema::GoalState &goal_state, std::map &sg_state_map); + OperationType get_operation_type(alcor::schema::OperationType operation_type); + Direction get_direction(alcor::schema::SecurityGroupConfiguration::Direction direction); + Ethertype get_ethertype(alcor::schema::EtherType ethertype); + Protocol get_protocol(alcor::schema::Protocol protocol); + int handle_port_security_group(Aca_Port &aca_port, Aca_Security_Group &aca_sg); +}; +} +#endif //ALCOR_CONTROL_AGENT_ACA_SG_STATE_HANDLER_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 643df590..a7b9a3e4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,7 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../build/bin) +add_definitions("-O0 -g") + set(SOURCES ./comm/aca_message_producer.cpp ./comm/aca_message_consumer.cpp @@ -15,8 +17,12 @@ set(SOURCES ./ovs/aca_ovs_control.cpp ./dhcp/aca_dhcp_state_handler.cpp ./dhcp/aca_dhcp_server.cpp + ./sg/aca_sg_state_handler.cpp + ./sg/aca_security_group.cpp + ./sg/aca_security_group_manager.cpp + ./sg/aca_security_group_ovs.cpp ) -FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu NO_DEFAULT_PATH) +FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu /usr/local/lib NO_DEFAULT_PATH) #for centos FIND_LIBRARY(CPPKAFKA cppkafka /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(OPENVSWITCH openvswitch /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(MESSAGEMANAGER messagemanager ${CMAKE_CURRENT_SOURCE_DIR}/../include NO_DEFAULT_PATH) diff --git a/src/comm/aca_comm_mgr.cpp b/src/comm/aca_comm_mgr.cpp index 573cf336..785dab54 100644 --- a/src/comm/aca_comm_mgr.cpp +++ b/src/comm/aca_comm_mgr.cpp @@ -17,12 +17,14 @@ #include "aca_comm_mgr.h" #include "aca_goal_state_handler.h" #include "aca_dhcp_state_handler.h" +#include "aca_sg_state_handler.h" #include "goalstateprovisioner.grpc.pb.h" using namespace std; using namespace alcor::schema; using namespace aca_goal_state_handler; using namespace aca_dhcp_state_handler; +using namespace aca_security_group; extern string g_rpc_server; extern string g_rpc_protocol; @@ -126,6 +128,17 @@ int Aca_Comm_Manager::update_goal_state(GoalState &goal_state_message, rc = exec_command_rc; } + if (goal_state_message.security_group_states_size() > 0) { + exec_command_rc = Aca_Sg_State_Handler::get_instance().update_security_group_states( + goal_state_message, gsOperationReply); + if (exec_command_rc == EXIT_SUCCESS) { + ACA_LOG_INFO("Successfully security group states, rc: %d\n", exec_command_rc); + } else { + ACA_LOG_ERROR("Failed to security group states. rc: %d\n", exec_command_rc); + rc = exec_command_rc; + } + } + auto end = chrono::steady_clock::now(); auto message_total_operation_time = cast_to_nanoseconds(end - start).count(); diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index ab099296..2709b39f 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -322,7 +322,7 @@ void ACA_OVS_L2_Programmer::execute_ovsdb_command(const std::string cmd_string, auto ovsdb_client_start = chrono::steady_clock::now(); - string ovsdb_cmd_string = "/usr/bin/ovs-vsctl " + cmd_string; + string ovsdb_cmd_string = "ovs-vsctl " + cmd_string; int rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(ovsdb_cmd_string); if (rc != EXIT_SUCCESS) { @@ -349,7 +349,7 @@ void ACA_OVS_L2_Programmer::execute_openflow_command(const std::string cmd_strin auto openflow_client_start = chrono::steady_clock::now(); - string openflow_cmd_string = "/usr/bin/ovs-ofctl " + cmd_string; + string openflow_cmd_string = "ovs-ofctl " + cmd_string; int rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(openflow_cmd_string); if (rc != EXIT_SUCCESS) { diff --git a/src/sg/aca_security_group.cpp b/src/sg/aca_security_group.cpp new file mode 100644 index 00000000..c0a384a5 --- /dev/null +++ b/src/sg/aca_security_group.cpp @@ -0,0 +1,295 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// 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 "aca_security_group.h" + +using namespace std; + + +namespace aca_security_group { + +void Aca_Security_Group_Rule::set_id(string id) { + this->id = id; +} + +string Aca_Security_Group_Rule::get_id(void) { + return this->id; +} + +void Aca_Security_Group_Rule::set_name(string name) { + this->name = name; +} + + +string Aca_Security_Group_Rule::get_name(void) { + return this->name; +} + +void Aca_Security_Group_Rule::set_cookie(uint64_t cookie) { + this->cookie = cookie; +} + +uint64_t Aca_Security_Group_Rule::get_cookie(void) { + return this->cookie; +} + +void Aca_Security_Group_Rule::set_direction(Direction direction) { + this->direction = direction; +} + +Direction Aca_Security_Group_Rule::get_direction(void) { + return this->direction; +} + +void Aca_Security_Group_Rule::set_ethertype(Ethertype ethertype) { + this->ethertype = ethertype; + +} + +Ethertype Aca_Security_Group_Rule::get_ethertype(void) { + return this->ethertype; +} + +void Aca_Security_Group_Rule::set_protocol(Protocol protocol) { + this->protocol = protocol; + +} +Protocol Aca_Security_Group_Rule::get_protocol(void) { + return this->protocol; +} + +void Aca_Security_Group_Rule::set_port_range_min(uint32_t port_range_min) { + this->port_range_min = port_range_min; +} + +uint32_t Aca_Security_Group_Rule::get_port_range_min(void) { + return this->port_range_min; +} + +void Aca_Security_Group_Rule::set_port_range_max(uint32_t port_range_max) { + this->port_range_max = port_range_max; +} + +uint32_t Aca_Security_Group_Rule::get_port_range_max(void) { + return this->port_range_max; +} + +void Aca_Security_Group_Rule::set_remote_ip_prefix(string remote_ip_prefix) { + this->remote_ip_prefix = remote_ip_prefix; +} + +string Aca_Security_Group_Rule::get_remote_ip_prefix(void) { + return this->remote_ip_prefix; +} + +void Aca_Security_Group_Rule::set_remote_group_id(string remote_group_id) { + this->remote_group_id = remote_group_id; +} + +string Aca_Security_Group_Rule::get_remote_group_id(void) { + return this->remote_group_id; +} + +void Aca_Security_Group_Rule::set_operation_type(OperationType operation_type) { + this->operation_type = operation_type; +} + +OperationType Aca_Security_Group_Rule::get_operation_type(void) { + return this->operation_type; +} + +void Aca_Security_Group::set_id(string id) { + this->id = id; +} + +string Aca_Security_Group::get_id(void) { + return this->id; +} + +void Aca_Security_Group::set_name(string name) { + this->name = name; +} + +string Aca_Security_Group::get_name(void) { + return this->name; +} +void Aca_Security_Group::set_format_version(uint32_t format_version) { + this->format_version = format_version; +} +uint32_t Aca_Security_Group::get_format_version(void) { + return this->format_version; +} +void Aca_Security_Group::set_revision_number(uint32_t revision_number) { + this->revision_number = revision_number; +} +uint32_t Aca_Security_Group::get_revision_number(void) { + return this->revision_number; +} + +void Aca_Security_Group::set_vpc_id(string vpc_id) { + this->vpc_id = vpc_id; +} +string Aca_Security_Group::get_vpc_id(void) { + return this->vpc_id; +} + +void Aca_Security_Group::set_operation_type(OperationType operation_type) { + this->operation_type = operation_type; +} + +OperationType Aca_Security_Group::get_operation_type(void) { + return this->operation_type; +} + +void Aca_Security_Group::add_security_group_rule(Aca_Security_Group_Rule *sg_rule) { + this->rules[sg_rule->get_id()] = sg_rule; +} + +void Aca_Security_Group::update_security_group_rule(Aca_Security_Group_Rule *sg_rule) { + Aca_Security_Group_Rule *old_sg_rule = get_security_group_rule(sg_rule->get_id()); + if (old_sg_rule != NULL) { + delete old_sg_rule; + } + + this->rules[sg_rule->get_id()] = sg_rule; +} + +void Aca_Security_Group::delete_security_group_rule(string sg_rule_id) { + Aca_Security_Group_Rule *old_sg_rule = get_security_group_rule(sg_rule_id); + if (old_sg_rule != NULL) { + this->rules.erase(sg_rule_id); + delete old_sg_rule; + } +} + + +Aca_Security_Group_Rule* Aca_Security_Group::get_security_group_rule(string sg_rule_id) { + map::iterator iterator = this->rules.find(sg_rule_id); + if (iterator != this->rules.end()) { + return iterator->second; + } + + return NULL; +} +map Aca_Security_Group::get_security_group_rules(void) { + return this->rules; +} + +void Aca_Port::set_id(string id) { + this->id = id; +} + +string Aca_Port::get_id(void) { + return this->id; +} + +void Aca_Port::set_name(string name) { + this->name = name; +} + +string Aca_Port::get_name(void) { + return this->name; +} + +void Aca_Port::set_ofport(uint32_t ofport) { + this->ofport = ofport; +} + +uint32_t Aca_Port::get_ofport(void) { + return this->ofport; +} + +void Aca_Port::set_format_version(uint32_t format_version) { + this->format_version = format_version; +} +uint32_t Aca_Port::get_format_version(void) { + return this->format_version; +} +void Aca_Port::set_revision_number(uint32_t revision_number) { + this->revision_number = revision_number; +} +uint32_t Aca_Port::get_revision_number(void) { + return this->revision_number; +} + +void Aca_Port::set_vpc_id(string vpc_id) { + this->vpc_id = vpc_id; +} + +string Aca_Port::get_vpc_id(void) { + return this->vpc_id; +} + +void Aca_Port::set_mac_address(string mac_address) { + this->mac_address = mac_address; +} + +string Aca_Port::get_mac_address(void) { + return this->mac_address; +} + +void Aca_Port::add_fixed_ip(string fixed_ip) { + this->fixed_ips.push_back(fixed_ip); +} + +void Aca_Port::add_security_group_id(string security_group_id) { + this->security_group_ids.push_back(security_group_id); +} + +void Aca_Port::delete_security_group_id(string security_group_id) { + vector::iterator it; + for (it = this->security_group_ids.begin(); it != this->security_group_ids.end(); ++it) { + if (*it == security_group_id) { + it = this->security_group_ids.erase(it); + break; + } + } +} + +int Aca_Port::get_security_group_id_num(void) { + return this->security_group_ids.size(); +} + +void Aca_Port::add_allow_address_pair(string ip_address, string mac_address) { + pair allow_address_pair(ip_address, mac_address); + this->allow_address_pairs.push_back(allow_address_pair); +} + +int Aca_Port::allow_address_pairs_size(void) +{ + return this->allow_address_pairs.size(); +} + +vector> Aca_Port::get_allow_address_pairs() +{ + return this->allow_address_pairs; +} + +void Aca_Port::add_security_group(Aca_Security_Group *security_group) { + this->security_groups.insert(pair(security_group->get_id(), security_group)); +} + +Aca_Security_Group *Aca_Port::get_security_group(string sg_id) { + map::iterator iterator = this->security_groups.find(sg_id); + if (iterator != this->security_groups.end()) { + return iterator->second; + } + + return NULL; +} + + +} diff --git a/src/sg/aca_security_group_manager.cpp b/src/sg/aca_security_group_manager.cpp new file mode 100644 index 00000000..110ad10a --- /dev/null +++ b/src/sg/aca_security_group_manager.cpp @@ -0,0 +1,220 @@ +// Copyright 2019 The Alcor Authors. +// +// 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 "aca_log.h" +#include "aca_security_group.h" +#include "aca_security_group_manager.h" +#include "aca_security_group_ovs.h" + +using namespace std; + +namespace aca_security_group { + +Aca_Security_Group_Manager &Aca_Security_Group_Manager::get_instance() +{ + // It is instantiated on first use. + // allocated instance is destroyed when program exits. + static Aca_Security_Group_Manager instance; + return instance; +} + +int Aca_Security_Group_Manager::create_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group &sg, + Aca_Security_Group_Rule &sg_rule) +{ + string rule_id; + Aca_Security_Group_Rule *aca_sg_rule; + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + rule_id = sg_rule.get_id(); + + aca_sg_rule = sg.get_security_group_rule(rule_id); + if (aca_sg_rule != NULL) { + TRN_LOG_WARN("Security group rule(id:%s) already exist", rule_id.data()); + return update_security_group_rule(aca_port, sg, sg_rule); + } + + sg_rule.set_cookie(0); + sg_ovs.create_port_security_group_rule(aca_port, sg_rule); + sg.add_security_group_rule(&sg_rule); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::update_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group &sg, + Aca_Security_Group_Rule &sg_rule) +{ + string rule_id; + Aca_Security_Group_Rule *aca_sg_rule; + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + rule_id = sg_rule.get_id(); + + aca_sg_rule = sg.get_security_group_rule(rule_id); + if (aca_sg_rule == NULL) { + ACA_LOG_ERROR("Can not find security group rule by id:%s", rule_id.data()); + return EXIT_FAILURE; + } + + sg_rule.set_cookie(aca_sg_rule->get_cookie() + 1); + sg_ovs.update_port_security_group_rule(aca_port, sg_rule); + sg.update_security_group_rule(&sg_rule); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::delete_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group &sg, + Aca_Security_Group_Rule &sg_rule) +{ + string rule_id; + Aca_Security_Group_Rule *aca_sg_rule; + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + rule_id = sg_rule.get_id(); + + aca_sg_rule = sg.get_security_group_rule(rule_id); + if (aca_sg_rule == NULL) { + ACA_LOG_ERROR("Can not find security group rule by id:%s", rule_id.data()); + return EXIT_FAILURE; + } + + sg_ovs.delete_port_security_group_rule(aca_port, *aca_sg_rule); + sg.delete_security_group_rule(sg_rule.get_id()); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::create_security_group(Aca_Port &aca_port, + Aca_Security_Group &aca_sg) + { + map::iterator piter; + map::iterator siter; + Aca_Security_Group *sg; + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + string port_id = aca_port.get_id(); + string sg_id = aca_sg.get_id(); + + piter = this->ports.find(port_id); + if (piter == this->ports.end()) { + sg_ovs.init_port(aca_port); + } + + siter = this->security_groups.find(sg_id); + if (siter == this->security_groups.end()) { + sg = new Aca_Security_Group(); + } else { + sg = siter->second; + } + + for (auto &it : aca_sg.get_security_group_rules()) { + create_security_group_rule(aca_port, *sg, *(it.second)); + } + + if (piter == this->ports.end()) { + this->ports[port_id] = &aca_port; + } else { + Aca_Port * aca_port = piter->second; + aca_port->add_security_group_id(sg_id); + } + + //TODO: maybe multi threads access this map + if (siter == this->security_groups.end()) { + this->security_groups[sg_id] = sg; + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::update_security_group(Aca_Port &aca_port, + Aca_Security_Group &aca_sg) +{ + map::iterator piter; + map::iterator siter; + + string port_id = aca_port.get_id(); + string sg_id = aca_sg.get_id(); + + piter = this->ports.find(port_id); + if (piter == this->ports.end()) { + ACA_LOG_ERROR("Can not find port by id:%s", port_id.data()); + return EXIT_FAILURE; + } + + siter = this->security_groups.find(sg_id); + if (siter == this->security_groups.end()) { + ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); + return EXIT_FAILURE; + } + + for (auto &it : aca_sg.get_security_group_rules()) { + Aca_Security_Group_Rule *sg_rule = it.second; + switch (sg_rule->get_operation_type()) { + case CREATE: + create_security_group_rule(aca_port, *(siter->second), *sg_rule); + break; + case UPDATE: + update_security_group_rule(aca_port, *(siter->second), *sg_rule); + break; + case DELETE: + delete_security_group_rule(aca_port, *(siter->second), *sg_rule); + break; + default: + ACA_LOG_ERROR("Invalid security group rule operation type"); + } + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::delete_security_group(Aca_Port &aca_port, + Aca_Security_Group &aca_sg) +{ + map::iterator piter; + map::iterator siter; + + string port_id = aca_port.get_id(); + string sg_id = aca_sg.get_id(); + + piter = this->ports.find(port_id); + if (piter == this->ports.end()) { + ACA_LOG_ERROR("Can not find port by id:%s", port_id.data()); + return EXIT_FAILURE; + } + + siter = this->security_groups.find(sg_id); + if (siter == this->security_groups.end()) { + ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); + return EXIT_FAILURE; + } + + + for (auto &it : aca_sg.get_security_group_rules()) { + Aca_Security_Group_Rule *sg_rule = it.second; + delete_security_group_rule(aca_port, *(siter->second), *sg_rule); + } + + aca_port.delete_security_group_id(sg_id); + + if (aca_port.get_security_group_id_num() == 0) { + Aca_Port *port = piter->second; + this->ports.erase(port_id); + delete port; + } + + //TODO: only delete sg when never be used by any port + //this->security_groups.erase(aca_sg.get_id()); + + return EXIT_SUCCESS; +} + +} diff --git a/src/sg/aca_security_group_mizar.cpp b/src/sg/aca_security_group_mizar.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/sg/aca_security_group_ovs.cpp b/src/sg/aca_security_group_ovs.cpp new file mode 100644 index 00000000..2559f515 --- /dev/null +++ b/src/sg/aca_security_group_ovs.cpp @@ -0,0 +1,330 @@ +// Copyright 2019 The Alcor Authors. +// +// 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 +#include "aca_log.h" +#include "aca_security_group_ovs.h" +#include "aca_ovs_control.h" + +using namespace aca_ovs_control; + +namespace aca_security_group { + +Aca_Security_Group_Ovs &Aca_Security_Group_Ovs::get_instance() +{ + // It is instantiated on first use. + // allocated instance is destroyed when program exits. + static Aca_Security_Group_Ovs instance; + return instance; +} + +int Aca_Security_Group_Ovs::get_vlan_by_segment_id(const int segment_id) +{ + return segment_id; +} + +void Aca_Security_Group_Ovs::init_port_egress_flows(Aca_Port &aca_port) +{ + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + char flow[128] = {0}; + + string port_id = aca_port.get_id(); + string vpc_id = aca_port.get_vpc_id(); + const char *mac_address = aca_port.get_mac_address().data(); + int ofport = 12; + int patch_ofport = 13; + + int vni = 10; + int local_vlan = get_vlan_by_segment_id(vni); + + + // DHCP discovery + sprintf(flow, "table=%d,priority=80,in_port=%d,reg%d=%d,dl_type=0x%04x,nw_proto=%d," + "tp_src=68,tp_dst=67,actions=resubmit(,%d)", BASE_EGRESS_TABLE, ofport, REG_PORT, + ofport, ETHERTYPE_IP, PROTO_NUM_UDP, ACCEPT_OR_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); + + // Drop DHCP response from vm + sprintf(flow, "table=%d,priority=70,in_port=%d,reg%d=%d,dl_type=0x%04x,nw_proto=%d," + "tp_src=67,tp_dst=68,actions=resubmit(,%d)", BASE_EGRESS_TABLE, ofport, REG_PORT, + ofport, ETHERTYPE_IP, PROTO_NUM_UDP, DROPPED_TRAFFIC_TABLE); + controller.add_flow(BR_INT, flow); + + // Drop all remaining egress connections + sprintf(flow, "table=%d,priority=10,in_port=%d,reg%d=%d,actions=ct_clear,resubmit(,%d)", + BASE_EGRESS_TABLE, ofport, REG_PORT, ofport, DROPPED_TRAFFIC_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=90,dl_type=0x%04x,reg%d=%d,ct_state=+new-est," + "actions=ct(commit,zone=NXM_NX_REG%d[0..15]),resubmit(,%d)", + ACCEPT_OR_INGRESS_TABLE, ETHERTYPE_IP, REG_PORT, ofport, REG_NET, ACCEPTED_EGRESS_TRAFFIC_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=80,reg%d=%d,actions=resubmit(,%d)", + ACCEPT_OR_INGRESS_TABLE, REG_PORT, ofport, ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=12,dl_dst=%s,reg%d=%d,actions=output:%d", + ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, mac_address, REG_NET, local_vlan, ofport); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=10,dl_src=%s,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00," + "reg%d=%d,actions=output:%d", + ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, mac_address, REG_NET, local_vlan, patch_ofport); + controller.add_flow(BR_INT, flow); +} + +void Aca_Security_Group_Ovs::init_port_ingress_flows(const Aca_Port &aca_port) +{ + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + char flow[128] = {0}; + + int ofport = 12; + + sprintf(flow, "table=%d,priority=100,dl_type=0x%04x,reg%d=%d,actions=output:%d", + BASE_INGRESS_TABLE, ETHERTYPE_ARP, REG_PORT, ofport, ofport); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=95,reg%d=%d,dl_type=0x%04x,nw_proto=%d," + "tp_src=67,tp_dst=68,actions=output:%d", + BASE_INGRESS_TABLE, REG_PORT, ofport, ETHERTYPE_IP, PROTO_NUM_UDP, ofport); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=90,reg%d=%d,dl_type=0x%04x,ct_state=-trk," + "actions=ct(table=%d,zone=NXM_NX_REG%d[0..15])", + BASE_INGRESS_TABLE, REG_PORT, ofport, ETHERTYPE_IP, RULES_INGRESS_TABLE, REG_NET); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,ct_state=+trk,priority=80,reg%d=%d,actions=resubmit(,%d)", + BASE_INGRESS_TABLE, REG_PORT, ofport, RULES_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); +} + +void Aca_Security_Group_Ovs::init_port(Aca_Port &aca_port) +{ + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + char flow[128] = {0}; + + string port_id = aca_port.get_id(); + string vpc_id = aca_port.get_vpc_id(); + int ofport = 12; + int vni = 10; + int local_vlan = get_vlan_by_segment_id(vni); + + sprintf(flow, "table=%d,priority=100,in_port=%d,actions=set_field:%d->reg%d," + "set_field:%d->reg%d,resubmit(,%d)", TRANSIENT_TABLE, ofport, ofport, + REG_PORT, local_vlan, REG_NET, BASE_EGRESS_TABLE); + controller.add_flow(BR_INT, flow); + + // Allow address pairs + vector> address_pairs = aca_port.get_allow_address_pairs(); + for (auto iter = address_pairs.cbegin(); iter != address_pairs.cend(); iter++) { + //pair address_pair = aca_port.allow_address_pairs(i); + const char * ip_address = iter->first.data(); + const char *mac_address = iter->second.data(); + + sprintf(flow, "table=%d,priority=90,dl_dst=%s,dl_vlan=%d,actions=set_field:%d->reg%d," + "set_field:%d->reg%d,strip_vlan,resubmit(,%d)", TRANSIENT_TABLE, mac_address, + local_vlan, ofport, REG_PORT, local_vlan, REG_NET, BASE_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=95,in_port=%d,reg%d=%d,dl_src=%s,dl_type=0x%04x," + "arp_spa=%s,actions=resubmit(,%d)", BASE_EGRESS_TABLE, ofport, REG_PORT, ofport, + mac_address, ETHERTYPE_ARP, ip_address, ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=65,in_port=%d,reg%d=%d,dl_src=%s,dl_type=0x%04x," + "nw_src=%s,actions=ct(table=%d,zone=NXM_NX_REG%d[0..15])", BASE_EGRESS_TABLE, ofport, + REG_PORT, ofport, mac_address, ETHERTYPE_IP, ip_address, RULES_EGRESS_TABLE, REG_NET); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=100,dl_dst=%s,reg_net=%d," + "actions=set_field:%d->reg%d,resubmit(,%d)", + ACCEPT_OR_INGRESS_TABLE, mac_address, local_vlan, ofport, REG_PORT, BASE_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); + } + + init_port_egress_flows(aca_port); + + init_port_ingress_flows(aca_port); +} + +int Aca_Security_Group_Ovs::get_flow_priority(Aca_Security_Group_Rule &aca_sg_rule, + int conjunction) +{ + string remote_group_id = aca_sg_rule.get_remote_group_id(); + int conj_offset = 4; + + if (remote_group_id == "" || conjunction) { + conj_offset = 0; + } + + int protocol = aca_sg_rule.get_protocol(); + uint32_t port_range_min = aca_sg_rule.get_port_range_min(); + uint32_t port_range_max = aca_sg_rule.get_port_range_max(); + + if (protocol == PROTO_NUM_ICMP) { + if (port_range_min == 0) { + return 70 + 1; + } else if (port_range_max == 0) { + return 70 + 2; + } + } + + return 70 + conj_offset; +} + +int Aca_Security_Group_Ovs::get_dl_type_by_ether_type(uint32_t ethertype) +{ + return ethertype; +} + +string Aca_Security_Group_Ovs::get_nw_proto_by_protocol(uint32_t protocol) +{ + switch (protocol) { + case PROTO_NUM_TCP: + return "tcp"; + case PROTO_NUM_UDP: + return "udp"; + case PROTO_NUM_ICMP: + return "icmp"; + default: + ACA_LOG_ERROR("=====>wrong ether type\n"); + } + + return ""; +} + +void Aca_Security_Group_Ovs::build_flows_from_sg_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule, + bool has_actions, + vector &flows) +{ + stringstream match_fileds; + int priority; + string actions; + string nw_src_dst; + string tcp_udp_dst; + + uint64_t cookie = aca_sg_rule.get_cookie(); + uint32_t dl_type = aca_sg_rule.get_ethertype(); + uint32_t nw_proto = aca_sg_rule.get_protocol(); + Direction direction = aca_sg_rule.get_direction(); + uint32_t port_range_min = aca_sg_rule.get_port_range_min(); + uint32_t port_range_max = aca_sg_rule.get_port_range_max(); + string remote_ip_prefix = aca_sg_rule.get_remote_ip_prefix(); + string remote_group_id = aca_sg_rule.get_remote_group_id(); + uint32_t ofport = aca_port.get_ofport(); + + priority = get_flow_priority(aca_sg_rule, 0); + //dl_type = get_dl_type_by_ether_type(ethertype); + tcp_udp_dst = get_nw_proto_by_protocol(nw_proto); + + if (direction == INGRESS) { + actions = "actions=output:" + ofport; + match_fileds << "table=" << RULES_INGRESS_TABLE << ","; + } else { + actions = "actions=resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; + match_fileds << "table=" << RULES_EGRESS_TABLE << ","; + } + + if (has_actions) { + match_fileds << "cookie=" << cookie << ","; + } else { + match_fileds << "cookie=" << cookie << "/-1,"; + } + + match_fileds << "priority=" << priority << ","; + match_fileds << "dl_type=" << dl_type << ","; + match_fileds << "reg" << REG_PORT << "=" << ofport << ","; + + if (remote_ip_prefix != "") { + if (direction == INGRESS) { + nw_src_dst = "nw_src=" + remote_ip_prefix ; + match_fileds << "nw_src=" << remote_ip_prefix << ","; + } else { + nw_src_dst = "nw_dst=" + remote_ip_prefix; + match_fileds << "nw_dst=" << remote_ip_prefix << ","; + } + } + + if (nw_proto > 0) { + match_fileds << "nw_proto=" << nw_proto << ","; + } + + for (uint32_t i = port_range_min; i <= port_range_max; i++) { + stringstream ss; + string flow; + + ss << tcp_udp_dst << "_dst=" << i; + flow = match_fileds.str() + ss.str(); + + if (has_actions) { + flow = flow + "," + actions; + } + + flows.push_back(flow); + } +} + +int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule) +{ + vector flows; + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + + build_flows_from_sg_rule(aca_port, aca_sg_rule, true, flows); + + for (uint32_t i = 0; i < flows.size(); i++) { + controller.add_flow(BR_INT, flows[i].data()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::update_port_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule) +{ + vector flows; + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + + aca_sg_rule.set_cookie(aca_sg_rule.get_cookie() - 1); + delete_port_security_group_rule(aca_port, aca_sg_rule); + aca_sg_rule.set_cookie(aca_sg_rule.get_cookie() + 1); + + build_flows_from_sg_rule(aca_port, aca_sg_rule, true, flows); + + for (uint32_t i = 0; i < flows.size(); i++) { + controller.add_flow(BR_INT, flows[i].data()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::delete_port_security_group_rule(Aca_Port &aca_port, + Aca_Security_Group_Rule &aca_sg_rule) +{ + vector flows; + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + + build_flows_from_sg_rule(aca_port, aca_sg_rule, false, flows); + + for (uint32_t i = 0; i < flows.size(); i++) { + controller.del_flows(BR_INT, flows[i].data()); + } + + return EXIT_SUCCESS; +} + +} diff --git a/src/sg/aca_sg_state_handler.cpp b/src/sg/aca_sg_state_handler.cpp new file mode 100644 index 00000000..4526caa4 --- /dev/null +++ b/src/sg/aca_sg_state_handler.cpp @@ -0,0 +1,248 @@ +// Copyright 2019 The Alcor Authors. +// +// 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 +#include "aca_log.h" +#include "aca_util.h" +#include "aca_sg_state_handler.h" +#include "aca_goal_state_handler.h" +#include "goalstateprovisioner.grpc.pb.h" +#include "aca_security_group_manager.h" + +using namespace std; +using namespace alcor::schema; + +namespace aca_security_group +{ +Aca_Sg_State_Handler::Aca_Sg_State_Handler() +{ + ACA_LOG_INFO("Sg State Handler: using sg server\n"); +} + +Aca_Sg_State_Handler::~Aca_Sg_State_Handler() +{ + // allocated sg_programming_if is destroyed when program exits. +} + +Aca_Sg_State_Handler &Aca_Sg_State_Handler::get_instance() +{ + // It is instantiated on first use. + // allocated instance is destroyed when program exits. + static Aca_Sg_State_Handler instance; + return instance; +} + +int Aca_Sg_State_Handler::handle_port_security_group(Aca_Port &aca_port, + Aca_Security_Group &aca_sg) +{ + Aca_Security_Group_Manager &sg_manager = Aca_Security_Group_Manager::get_instance(); + OperationType operation_type = aca_sg.get_operation_type(); + + switch (operation_type) { + case CREATE: + return sg_manager.create_security_group(aca_port, aca_sg); + case UPDATE: + return sg_manager.update_security_group(aca_port, aca_sg); + case DELETE: + return sg_manager.delete_security_group(aca_port, aca_sg); + default: + ACA_LOG_ERROR("=====>wrong security group operation\n"); + } + + delete &aca_sg; + + return EXIT_FAILURE; +} + +Aca_Port * Aca_Sg_State_Handler::parse_port_state(const PortState &port_state) +{ + PortConfiguration port_config = port_state.configuration(); + + //TODO: verify fields of port_state + Aca_Port *aca_port = new Aca_Port(); + aca_port->set_id(port_config.id()); + aca_port->set_mac_address(port_config.mac_address()); + + for (int i = 0; i < port_config.fixed_ips_size(); i++) { + aca_port->add_fixed_ip(port_config.fixed_ips(i).ip_address()); + } + + for (int i = 0; i < port_config.allow_address_pairs_size(); i++) { + PortConfiguration::AllowAddressPair pair = port_config.allow_address_pairs(i); + aca_port->add_allow_address_pair(pair.ip_address(), pair.mac_address()); + } + + for (int i = 0; i < port_config.security_group_ids_size(); i++) { + aca_port->add_security_group_id(port_config.security_group_ids(i).id()); + } + + return aca_port; +} + +OperationType Aca_Sg_State_Handler::get_operation_type(alcor::schema::OperationType operation_type) +{ + switch(operation_type) { + case alcor::schema::OperationType::CREATE: + return CREATE; + case alcor::schema::OperationType::UPDATE: + return UPDATE; + case alcor::schema::OperationType::DELETE: + return DELETE; + default: + ACA_LOG_ERROR("Invalid operation type"); + } + + throw "Invalid operation type"; +} + +Direction Aca_Sg_State_Handler::get_direction(SecurityGroupConfiguration::Direction direction) +{ + switch(direction) { + case SecurityGroupConfiguration::EGRESS: + return EGRESS; + case SecurityGroupConfiguration::INGRESS: + return INGRESS; + default: + ACA_LOG_ERROR("Invalid direction"); + } + + + throw "Invalid direction"; +} + +Ethertype Aca_Sg_State_Handler::get_ethertype(alcor::schema::EtherType ethertype) +{ + switch(ethertype) { + case alcor::schema::EtherType::IPV4: + return IPV4; + case alcor::schema::EtherType::IPV6: + return IPV6; + default: + ACA_LOG_ERROR("Invalid ethertype"); + } + + throw "Invalid ethertype"; +} + +Protocol Aca_Sg_State_Handler::get_protocol(alcor::schema::Protocol protocol) +{ + switch(protocol) { + case alcor::schema::Protocol::TCP: + return TCP; + case alcor::schema::Protocol::UDP: + return UDP; + case alcor::schema::Protocol::ICMP: + return ICMP; + default: + ACA_LOG_ERROR("Invalid protocol"); + } + + throw "Invalid protocol"; +} + + +void Aca_Sg_State_Handler::parse_security_group_states(const GoalState &goal_state, + map &aca_sg_map) +{ + //TODO: verify fields of port_state + for (int i = 0; i < goal_state.security_group_states_size(); i++) { + ACA_LOG_DEBUG("=====>parsing security group states #%d\n", i); + + Aca_Security_Group *aca_sg; + SecurityGroupState sg_state = goal_state.security_group_states(i); + SecurityGroupConfiguration sg_config = sg_state.configuration(); + + if (sg_config.id() == "") { + ACA_LOG_ERROR("Security group id is empty"); + continue; + } + + aca_sg = new Aca_Security_Group(); + + aca_sg->set_id(sg_config.id()); + aca_sg->set_name(sg_config.name()); + aca_sg->set_vpc_id(sg_config.vpc_id()); + aca_sg->set_format_version(sg_config.format_version()); + aca_sg->set_revision_number(sg_config.revision_number()); + aca_sg->set_operation_type(get_operation_type(sg_state.operation_type())); + + for (int j = 0; j < sg_config.security_group_rules_size(); j++) { + SecurityGroupConfiguration::SecurityGroupRule sg_rule = sg_config.security_group_rules(i); + Aca_Security_Group_Rule *aca_sg_rule = new Aca_Security_Group_Rule(); + + if (sg_config.id() == "") { + ACA_LOG_ERROR("Security group rule id is empty"); + continue; + } + + aca_sg_rule->set_id(sg_rule.id()); + aca_sg_rule->set_direction(get_direction(sg_rule.direction())); + aca_sg_rule->set_ethertype(get_ethertype(sg_rule.ethertype())); + aca_sg_rule->set_protocol(get_protocol(sg_rule.protocol())); + aca_sg_rule->set_port_range_min(sg_rule.port_range_min()); + aca_sg_rule->set_port_range_max(sg_rule.port_range_max()); + aca_sg_rule->set_remote_ip_prefix(sg_rule.remote_ip_prefix()); + aca_sg_rule->set_remote_group_id(sg_rule.remote_group_id()); + aca_sg_rule->set_operation_type(get_operation_type(sg_rule.operation_type())); + + aca_sg->add_security_group_rule(aca_sg_rule); + } + + aca_sg_map[sg_config.id()] = aca_sg; + } +} + +int Aca_Sg_State_Handler::update_security_group_states(const GoalState &goal_state, + GoalStateOperationReply &reply) +{ + std::vector> futures; + int rc; + int overall_rc = EXIT_SUCCESS; + map aca_sg_map; + + parse_security_group_states(goal_state, aca_sg_map); + + for (int i = 0; i < goal_state.port_states_size(); i++) { + PortState port_state = goal_state.port_states(i); + PortConfiguration port_config = port_state.configuration(); + + Aca_Port *aca_port = parse_port_state(port_state); + + for (int j = 0; j < port_config.security_group_ids_size(); j++) { + PortConfiguration::SecurityGroupId security_group_id = port_config.security_group_ids(j); + string sg_id = security_group_id.id(); + + map::iterator iterator = aca_sg_map.find(sg_id); + if (iterator == aca_sg_map.end()) { + ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); + continue; + } + + futures.push_back(std::async( + std::launch::async, &Aca_Sg_State_Handler::handle_port_security_group, + this, std::ref(*aca_port), std::ref(*(iterator->second)))); + } + } + + for (uint32_t i = 0; i < futures.size(); i++) { + rc = futures[i].get(); + if (rc != EXIT_SUCCESS) { + overall_rc = rc; + } + } + + return overall_rc; +} + +} diff --git a/test/aca-sg-test/.idea/.gitignore b/test/aca-sg-test/.idea/.gitignore new file mode 100644 index 00000000..5c98b428 --- /dev/null +++ b/test/aca-sg-test/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml b/test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/compiler.xml b/test/aca-sg-test/.idea/compiler.xml new file mode 100644 index 00000000..45f38519 --- /dev/null +++ b/test/aca-sg-test/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/encodings.xml b/test/aca-sg-test/.idea/encodings.xml new file mode 100644 index 00000000..b26911bd --- /dev/null +++ b/test/aca-sg-test/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/misc.xml b/test/aca-sg-test/.idea/misc.xml new file mode 100644 index 00000000..e6a9feae --- /dev/null +++ b/test/aca-sg-test/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/vcs.xml b/test/aca-sg-test/.idea/vcs.xml new file mode 100644 index 00000000..b2bdec2d --- /dev/null +++ b/test/aca-sg-test/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/aca-sg-test.iml b/test/aca-sg-test/aca-sg-test.iml new file mode 100644 index 00000000..78b2cc53 --- /dev/null +++ b/test/aca-sg-test/aca-sg-test.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/aca-sg-test/pom.xml b/test/aca-sg-test/pom.xml new file mode 100644 index 00000000..da63f813 --- /dev/null +++ b/test/aca-sg-test/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + com.futurewei + aca-sg-test + 1.0-SNAPSHOT + + + UTF-8 + 11 + 11 + + + + + com.futurewei.alcor + schema + 0.1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java b/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java new file mode 100644 index 00000000..fb57f689 --- /dev/null +++ b/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java @@ -0,0 +1,145 @@ +/* +Copyright 2019 The Alcor Authors. + +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. +*/ +package com.futurewei.aca.securitygroup; + +import com.futurewei.alcor.schema.Common; +import com.futurewei.alcor.schema.Common.EtherType; +import com.futurewei.alcor.schema.Common.Protocol; +import com.futurewei.alcor.schema.Common.OperationType; +import com.futurewei.alcor.schema.Vpc.VpcState; +import com.futurewei.alcor.schema.Vpc.VpcConfiguration; +import com.futurewei.alcor.schema.Subnet.SubnetState; +import com.futurewei.alcor.schema.Subnet.SubnetConfiguration; +import com.futurewei.alcor.schema.Port.PortState; +import com.futurewei.alcor.schema.Port.PortConfiguration; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupState; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupConfiguration; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupConfiguration.SecurityGroupRule; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupConfiguration.Direction; +import com.futurewei.alcor.schema.GoalStateProvisionerGrpc.GoalStateProvisionerBlockingStub; +import com.futurewei.alcor.schema.GoalStateProvisionerGrpc; +import com.futurewei.alcor.schema.Goalstate.GoalState; +import com.futurewei.alcor.schema.Goalstateprovisioner.GoalStateOperationReply; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +public class SecurityGroupTest { + private ManagedChannel managedChannel; + + public SecurityGroupTest() { + this.managedChannel = ManagedChannelBuilder.forAddress("192.168.131.131",50001) + .usePlaintext().build(); + } + + private VpcState buildVpcState() { + VpcConfiguration.Builder vpcConfigBuilder = VpcConfiguration.newBuilder(); + vpcConfigBuilder.setName("vpc1"); + vpcConfigBuilder.setCidr("10.10.10.0/24"); + vpcConfigBuilder.setId("vpc_id1"); + + VpcState.Builder vpcStateBuilder = VpcState.newBuilder(); + vpcStateBuilder.setOperationType(OperationType.CREATE); + vpcStateBuilder.setConfiguration(vpcConfigBuilder.build()); + + return vpcStateBuilder.build(); + } + + private SubnetState buildSubnetState() { + SubnetConfiguration.Builder subnetConfigBuilder = SubnetConfiguration.newBuilder(); + subnetConfigBuilder.setName("subnet1"); + subnetConfigBuilder.setCidr("10.10.10.0/24"); + subnetConfigBuilder.setId("subnet_id1"); + + SubnetState.Builder subnetStateBuilder = SubnetState.newBuilder(); + subnetStateBuilder.setOperationType(OperationType.CREATE); + subnetStateBuilder.setConfiguration(subnetConfigBuilder.build()); + + return subnetStateBuilder.build(); + } + + private PortState buildPortState() { + PortConfiguration.Builder portConfigBuilder = PortConfiguration.newBuilder(); + portConfigBuilder.setName("port1"); + portConfigBuilder.setVpcId("vpc_id1"); + portConfigBuilder.setId("port_id1"); + portConfigBuilder.setFormatVersion(1); + portConfigBuilder.setRevisionNumber(1); + portConfigBuilder.setAdminStateUp(true); + portConfigBuilder.setMessageType(Common.MessageType.FULL); + portConfigBuilder.setMacAddress("7E:04:D0:C9:12:6C"); + portConfigBuilder.addFixedIps(PortConfiguration.FixedIp.newBuilder() + .setIpAddress("10.10.10.2").setSubnetId("subnet_id1").build()); + PortConfiguration.SecurityGroupId.Builder securityGroupIdBuilder = PortConfiguration.SecurityGroupId.newBuilder(); + securityGroupIdBuilder.setId("security_group_id1"); + portConfigBuilder.addSecurityGroupIds(securityGroupIdBuilder.build()); + + PortState.Builder portStateBuilder = PortState.newBuilder(); + portStateBuilder.setOperationType(OperationType.CREATE); + portStateBuilder.setConfiguration(portConfigBuilder.build()); + + return portStateBuilder.build(); + } + + private SecurityGroupState buildSecurityGroupState() { + SecurityGroupConfiguration.Builder securityGroupConfigBuilder = SecurityGroupConfiguration.newBuilder(); + securityGroupConfigBuilder.setName("security_group1"); + securityGroupConfigBuilder.setVpcId("vpc_id1"); + securityGroupConfigBuilder.setId("security_group_id1"); + securityGroupConfigBuilder.setFormatVersion(1); + securityGroupConfigBuilder.setRevisionNumber(1); + SecurityGroupRule.Builder securityGroupRuleBuilder = SecurityGroupRule.newBuilder(); + securityGroupRuleBuilder.setOperationType(OperationType.CREATE); + securityGroupRuleBuilder.setId("security_group_rule_id1"); + securityGroupRuleBuilder.setSecurityGroupId("security_group_id1"); + securityGroupRuleBuilder.setDirection(Direction.EGRESS); + securityGroupRuleBuilder.setEthertype(EtherType.IPV4); + securityGroupRuleBuilder.setProtocol(Protocol.TCP); + securityGroupRuleBuilder.setPortRangeMin(100); + securityGroupRuleBuilder.setPortRangeMax(101); + securityGroupRuleBuilder.setRemoteIpPrefix("12.12.12.0/24"); + securityGroupConfigBuilder.addSecurityGroupRules(securityGroupRuleBuilder.build()); + + SecurityGroupState.Builder securityGroupStateBuilder = SecurityGroupState.newBuilder(); + securityGroupStateBuilder.setOperationType(OperationType.CREATE); + securityGroupStateBuilder.setConfiguration(securityGroupConfigBuilder.build()); + + return securityGroupStateBuilder.build(); + } + + public void pushNetworkResourceStatesTest() { + GoalStateProvisionerBlockingStub blockingStub = + GoalStateProvisionerGrpc.newBlockingStub(managedChannel); + + GoalState.Builder builder = GoalState.newBuilder(); + builder.setFormatVersion(1); + builder.addVpcStates(buildVpcState()); + builder.addSubnetStates(buildSubnetState()); + builder.addPortStates(buildPortState()); + builder.addSecurityGroupStates(buildSecurityGroupState()); + + GoalStateOperationReply goalStateOperationReply + = blockingStub.pushNetworkResourceStates(builder.build()); + + System.out.println(goalStateOperationReply.toString()); + + managedChannel.shutdown(); + } + + public static void main(String[] args) { + SecurityGroupTest securityGroupTest = new SecurityGroupTest(); + securityGroupTest.pushNetworkResourceStatesTest(); + } +} diff --git a/test/aca-sg-test/target/aca-sg-test-1.0-SNAPSHOT.jar b/test/aca-sg-test/target/aca-sg-test-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..3c254344ba0b83ecc848107719e3801e2125e903 GIT binary patch literal 4753 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 literal 0 HcmV?d00001 diff --git a/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class b/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class new file mode 100644 index 0000000000000000000000000000000000000000..4ac5c4674ba660ef8c3e9575cd41f02d7969a5e3 GIT binary patch literal 13662 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 literal 0 HcmV?d00001 diff --git a/test/aca-sg-test/target/maven-archiver/pom.properties b/test/aca-sg-test/target/maven-archiver/pom.properties new file mode 100644 index 00000000..c13c9b5e --- /dev/null +++ b/test/aca-sg-test/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Wed Oct 14 15:03:52 CST 2020 +groupId=com.futurewei +artifactId=aca-sg-test +version=1.0-SNAPSHOT diff --git a/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 00000000..fafceb50 --- /dev/null +++ b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +com\futurewei\aca\securitygroup\SecurityGroupTest.class diff --git a/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 00000000..0ab59aa8 --- /dev/null +++ b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1 @@ +F:\work\alcor\git\chenpp\alcor-control-agent\test\aca-sg-test\src\main\java\com\futurewei\aca\securitygroup\SecurityGroupTest.java diff --git a/test/aca-sg-test/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 00000000..e69de29b From f7258f7f643711690e3522c6bad17e2e397705c8 Mon Sep 17 00:00:00 2001 From: chenpiaoping Date: Tue, 20 Oct 2020 20:34:24 +0800 Subject: [PATCH 2/4] Implementation of conjunction flow --- include/aca_security_group.h | 22 +- include/aca_security_group_manager.h | 19 +- include/aca_security_group_ovs.h | 40 +-- src/sg/aca_security_group.cpp | 41 ++- src/sg/aca_security_group_manager.cpp | 161 ++++++++---- src/sg/aca_security_group_ovs.cpp | 349 ++++++++++++++++++++++---- src/sg/aca_sg_state_handler.cpp | 50 +++- 7 files changed, 530 insertions(+), 152 deletions(-) diff --git a/include/aca_security_group.h b/include/aca_security_group.h index fbffc174..cd775c7b 100644 --- a/include/aca_security_group.h +++ b/include/aca_security_group.h @@ -31,25 +31,30 @@ enum OperationType { CREATE=1, UPDATE, DELETE, + UNKNOWN_OPERATION, }; enum Direction { INGRESS=1, EGRESS, + UNKNOWN_DIRECTION, }; enum Ethertype { IPV4=0x0800, ARP=0x0806, - IPV6=0x86dd + IPV6=0x86dd, + UNKNOWN_ETHERTYPE, }; enum Protocol { TCP=6, UDP=17, - ICMP=1 + ICMP=1, + UNKNOWN_PROTO }; +class Aca_Security_Group; class Aca_Security_Group_Rule { public: @@ -76,6 +81,8 @@ class Aca_Security_Group_Rule { string get_remote_group_id(void); void set_operation_type(OperationType operation_type); OperationType get_operation_type(void); + void set_remote_group(Aca_Security_Group * remote_group); + Aca_Security_Group * get_remote_group(void); private: string id; @@ -89,6 +96,7 @@ class Aca_Security_Group_Rule { string remote_ip_prefix; string remote_group_id; OperationType operation_type; + Aca_Security_Group *remote_group; }; class Aca_Security_Group { @@ -105,6 +113,10 @@ class Aca_Security_Group { string get_vpc_id(void); void set_operation_type(OperationType operation_type); OperationType get_operation_type(void); + void add_port_id(string port_id); + void delete_port_id(string port_id); + int get_port_num(void); + vector &get_port_ids(void); void add_security_group_rule(Aca_Security_Group_Rule *sg_rule); void update_security_group_rule(Aca_Security_Group_Rule *sg_rule); void delete_security_group_rule(string sg_rule_id); @@ -117,7 +129,8 @@ class Aca_Security_Group { uint32_t format_version; uint32_t revision_number; string vpc_id; - OperationType operation_type; + OperationType operation_type; + vector port_ids; map rules; }; @@ -138,9 +151,10 @@ class Aca_Port { void set_mac_address(string mac_address); string get_mac_address(void); void add_fixed_ip(string fixed_ip); + vector &get_fixed_ip(void); void add_security_group_id(string security_group_id); void delete_security_group_id(string security_group_id); - int get_security_group_id_num(void); + int get_security_group_num(void); void add_allow_address_pair(string ip_address, string mac_address); int allow_address_pairs_size(void); vector> get_allow_address_pairs(void); diff --git a/include/aca_security_group_manager.h b/include/aca_security_group_manager.h index 86acfc34..74848c87 100644 --- a/include/aca_security_group_manager.h +++ b/include/aca_security_group_manager.h @@ -25,17 +25,22 @@ namespace aca_security_group { class Aca_Security_Group_Manager { public: static Aca_Security_Group_Manager &get_instance(); - int create_security_group_rule(Aca_Port &port_state, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); - int update_security_group_rule(Aca_Port &port_state, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); - int delete_security_group_rule(Aca_Port &port_state, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); - int create_security_group(Aca_Port &port_state, Aca_Security_Group &sg); - int update_security_group(Aca_Port &port_state, Aca_Security_Group &sg); - int delete_security_group(Aca_Port &port_state, Aca_Security_Group &sg); + int create_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int update_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int delete_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int create_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg); + int update_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg); + int delete_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg); + + map &get_ports(void); + map &get_security_groups(void); private: + int set_remote_group(Aca_Security_Group_Rule &sg_rule); + map ports; map security_groups; }; } -#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H \ No newline at end of file +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H diff --git a/include/aca_security_group_ovs.h b/include/aca_security_group_ovs.h index c9f2b932..c2bacf14 100644 --- a/include/aca_security_group_ovs.h +++ b/include/aca_security_group_ovs.h @@ -30,6 +30,7 @@ namespace aca_security_group { #define BASE_INGRESS_TABLE 81 #define RULES_INGRESS_TABLE 82 #define ACCEPTED_EGRESS_TRAFFIC_TABLE 91 +#define ACCEPTED_INGRESS_TRAFFIC_TABLE 92 #define DROPPED_TRAFFIC_TABLE 93 #define ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE 94 @@ -47,28 +48,37 @@ namespace aca_security_group { #define BR_INT "br-int" #define BR_TUN "br-tun" +#define FLOW_PRIORITY_BASE 70 + class Aca_Security_Group_Ovs { public: static Aca_Security_Group_Ovs &get_instance(); - void init_port(Aca_Port &aca_port); - int create_port_security_group_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule); - int update_port_security_group_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule); - int delete_port_security_group_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule); + void init_port(Aca_Port &port); + int create_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule); + int update_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule); + int delete_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule); private: int get_vlan_by_segment_id(const int segment_id); - void init_port_egress_flows(Aca_Port &aca_port); - void init_port_ingress_flows(const Aca_Port &aca_port); - int get_flow_priority(Aca_Security_Group_Rule &aca_sg_rule, int conjunction); + void init_port_egress_flows(Aca_Port &port); + void init_port_ingress_flows(const Aca_Port &port); + int flow_priority_offset(Aca_Security_Group_Rule &sg_rule, bool conjunction); int get_dl_type_by_ether_type(uint32_t ether_type); string get_nw_proto_by_protocol(uint32_t protocol); - void build_flows_from_sg_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule, - bool has_actions, - vector &flows); + int get_remote_group_conj_id(Aca_Security_Group_Rule &sg_rule); + int build_flows_by_sg_rule(Aca_Port &port,Aca_Security_Group_Rule &sg_rule,bool has_actions, vector &flows); + int build_conjunction_flows(Aca_Port &port, Aca_Security_Group_Rule &sg_rule,bool need_actions, vector &flows); + int get_remote_group_ips(Aca_Security_Group *remote_group, vector remote_ips); + int build_flows_by_remote_ip(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, string remote_ip, int conj_id, vector &flows); + int build_normal_flows(Aca_Port &port,Aca_Security_Group_Rule &sg_rule,bool need_actions, vector &flows); + int add_conjunction_actions(string _flow, int conj_id, int dimension, vector &flows); + int build_accept_flows(Aca_Port &port,Aca_Security_Group_Rule &sg_rule, int conj_id, vector &flows); + + uint64_t conj_id_base; + map conj_ids; }; } -#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H \ No newline at end of file +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H diff --git a/src/sg/aca_security_group.cpp b/src/sg/aca_security_group.cpp index c0a384a5..9e6bbd8e 100644 --- a/src/sg/aca_security_group.cpp +++ b/src/sg/aca_security_group.cpp @@ -111,6 +111,14 @@ OperationType Aca_Security_Group_Rule::get_operation_type(void) { return this->operation_type; } +void Aca_Security_Group_Rule::set_remote_group(Aca_Security_Group * remote_group) { + this->remote_group = remote_group; +} + +Aca_Security_Group * Aca_Security_Group_Rule::get_remote_group(void) { + return this->remote_group; +} + void Aca_Security_Group::set_id(string id) { this->id = id; } @@ -154,8 +162,31 @@ OperationType Aca_Security_Group::get_operation_type(void) { return this->operation_type; } +void Aca_Security_Group::add_port_id(string port_id) { + this->port_ids.push_back(port_id); +} + +void Aca_Security_Group::delete_port_id(string port_id) { + vector::iterator it; + for (it = this->port_ids.begin(); it != this->port_ids.end(); ++it) { + if (*it == port_id) { + it = this->port_ids.erase(it); + break; + } + } +} + +int Aca_Security_Group::get_port_num(void) { + return this->port_ids.size(); +} + +vector &Aca_Security_Group::get_port_ids(void) { + return this->port_ids; +} + void Aca_Security_Group::add_security_group_rule(Aca_Security_Group_Rule *sg_rule) { - this->rules[sg_rule->get_id()] = sg_rule; + Aca_Security_Group_Rule *new_sg_rule = new Aca_Security_Group_Rule(*sg_rule); + this->rules[new_sg_rule->get_id()] = new_sg_rule; } void Aca_Security_Group::update_security_group_rule(Aca_Security_Group_Rule *sg_rule) { @@ -164,7 +195,7 @@ void Aca_Security_Group::update_security_group_rule(Aca_Security_Group_Rule *sg_ delete old_sg_rule; } - this->rules[sg_rule->get_id()] = sg_rule; + add_security_group_rule(sg_rule); } void Aca_Security_Group::delete_security_group_rule(string sg_rule_id) { @@ -245,6 +276,10 @@ void Aca_Port::add_fixed_ip(string fixed_ip) { this->fixed_ips.push_back(fixed_ip); } +vector &Aca_Port::get_fixed_ip(void) { + return this->fixed_ips; +} + void Aca_Port::add_security_group_id(string security_group_id) { this->security_group_ids.push_back(security_group_id); } @@ -259,7 +294,7 @@ void Aca_Port::delete_security_group_id(string security_group_id) { } } -int Aca_Port::get_security_group_id_num(void) { +int Aca_Port::get_security_group_num(void) { return this->security_group_ids.size(); } diff --git a/src/sg/aca_security_group_manager.cpp b/src/sg/aca_security_group_manager.cpp index 110ad10a..4ec86a77 100644 --- a/src/sg/aca_security_group_manager.cpp +++ b/src/sg/aca_security_group_manager.cpp @@ -29,35 +29,66 @@ Aca_Security_Group_Manager &Aca_Security_Group_Manager::get_instance() return instance; } -int Aca_Security_Group_Manager::create_security_group_rule(Aca_Port &aca_port, +map &Aca_Security_Group_Manager::get_ports(void) +{ + return this->ports; +} + +map &Aca_Security_Group_Manager::get_security_groups(void) +{ + return this->security_groups; +} + +int Aca_Security_Group_Manager::set_remote_group(Aca_Security_Group_Rule &sg_rule) +{ + map::iterator iter; + string remote_grou_id = sg_rule.get_remote_group_id(); + + if (remote_grou_id != "") { + iter = this->security_groups.find(remote_grou_id); + if (iter == this->security_groups.end()) { + return EXIT_FAILURE; + } + + sg_rule.set_remote_group(iter->second); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::create_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule) { + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); string rule_id; Aca_Security_Group_Rule *aca_sg_rule; - Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); rule_id = sg_rule.get_id(); aca_sg_rule = sg.get_security_group_rule(rule_id); if (aca_sg_rule != NULL) { TRN_LOG_WARN("Security group rule(id:%s) already exist", rule_id.data()); - return update_security_group_rule(aca_port, sg, sg_rule); + return update_security_group_rule(port, sg, sg_rule); + } + + if (set_remote_group(sg_rule) != EXIT_SUCCESS) { + return EXIT_FAILURE; } sg_rule.set_cookie(0); - sg_ovs.create_port_security_group_rule(aca_port, sg_rule); + sg_ovs.create_port_security_group_rule(port, sg_rule); sg.add_security_group_rule(&sg_rule); return EXIT_SUCCESS; } -int Aca_Security_Group_Manager::update_security_group_rule(Aca_Port &aca_port, +int Aca_Security_Group_Manager::update_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule) { + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); string rule_id; Aca_Security_Group_Rule *aca_sg_rule; - Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); rule_id = sg_rule.get_id(); aca_sg_rule = sg.get_security_group_rule(rule_id); @@ -66,20 +97,24 @@ int Aca_Security_Group_Manager::update_security_group_rule(Aca_Port &aca_port, return EXIT_FAILURE; } + if (set_remote_group(sg_rule) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + sg_rule.set_cookie(aca_sg_rule->get_cookie() + 1); - sg_ovs.update_port_security_group_rule(aca_port, sg_rule); + sg_ovs.update_port_security_group_rule(port, sg_rule); sg.update_security_group_rule(&sg_rule); return EXIT_SUCCESS; } -int Aca_Security_Group_Manager::delete_security_group_rule(Aca_Port &aca_port, +int Aca_Security_Group_Manager::delete_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule) { + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); string rule_id; Aca_Security_Group_Rule *aca_sg_rule; - Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); rule_id = sg_rule.get_id(); aca_sg_rule = sg.get_security_group_rule(rule_id); @@ -87,86 +122,95 @@ int Aca_Security_Group_Manager::delete_security_group_rule(Aca_Port &aca_port, ACA_LOG_ERROR("Can not find security group rule by id:%s", rule_id.data()); return EXIT_FAILURE; } + + if (set_remote_group(sg_rule) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } - sg_ovs.delete_port_security_group_rule(aca_port, *aca_sg_rule); + sg_ovs.delete_port_security_group_rule(port, *aca_sg_rule); sg.delete_security_group_rule(sg_rule.get_id()); return EXIT_SUCCESS; } -int Aca_Security_Group_Manager::create_security_group(Aca_Port &aca_port, - Aca_Security_Group &aca_sg) +int Aca_Security_Group_Manager::create_security_group(Aca_Port &input_port, + Aca_Security_Group &input_sg) { + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); map::iterator piter; map::iterator siter; - Aca_Security_Group *sg; - Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); - string port_id = aca_port.get_id(); - string sg_id = aca_sg.get_id(); + Aca_Security_Group *aca_sg; + Aca_Port * aca_port; + string port_id = input_port.get_id(); + string sg_id = input_sg.get_id(); + //TODO: maybe multi threads access this map piter = this->ports.find(port_id); if (piter == this->ports.end()) { - sg_ovs.init_port(aca_port); + aca_port = new Aca_Port(input_port); + this->ports[port_id] = aca_port; + sg_ovs.init_port(*aca_port); + } else { + aca_port = piter->second; } siter = this->security_groups.find(sg_id); if (siter == this->security_groups.end()) { - sg = new Aca_Security_Group(); + aca_sg = new Aca_Security_Group(input_sg); + this->security_groups[sg_id] = aca_sg; } else { - sg = siter->second; + aca_sg = siter->second; } - for (auto &it : aca_sg.get_security_group_rules()) { - create_security_group_rule(aca_port, *sg, *(it.second)); - } - - if (piter == this->ports.end()) { - this->ports[port_id] = &aca_port; - } else { - Aca_Port * aca_port = piter->second; - aca_port->add_security_group_id(sg_id); - } + aca_sg->add_port_id(port_id); + aca_port->add_security_group_id(sg_id); - //TODO: maybe multi threads access this map - if (siter == this->security_groups.end()) { - this->security_groups[sg_id] = sg; - } + for (auto &it : input_sg.get_security_group_rules()) { + create_security_group_rule(*aca_port, *aca_sg, *(it.second)); + } return EXIT_SUCCESS; } -int Aca_Security_Group_Manager::update_security_group(Aca_Port &aca_port, - Aca_Security_Group &aca_sg) +int Aca_Security_Group_Manager::update_security_group(Aca_Port &input_port, + Aca_Security_Group &input_sg) { map::iterator piter; map::iterator siter; + Aca_Security_Group *aca_sg; + Aca_Port * aca_port; - string port_id = aca_port.get_id(); - string sg_id = aca_sg.get_id(); + string port_id = input_port.get_id(); + string sg_id = input_sg.get_id(); + //TODO: do we need to update the port ? piter = this->ports.find(port_id); if (piter == this->ports.end()) { ACA_LOG_ERROR("Can not find port by id:%s", port_id.data()); return EXIT_FAILURE; } + + aca_port = piter->second; siter = this->security_groups.find(sg_id); if (siter == this->security_groups.end()) { ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); return EXIT_FAILURE; } + + aca_sg = siter->second; - for (auto &it : aca_sg.get_security_group_rules()) { + for (auto &it : input_sg.get_security_group_rules()) { Aca_Security_Group_Rule *sg_rule = it.second; switch (sg_rule->get_operation_type()) { case CREATE: - create_security_group_rule(aca_port, *(siter->second), *sg_rule); + create_security_group_rule(*aca_port, *aca_sg, *sg_rule); break; case UPDATE: - update_security_group_rule(aca_port, *(siter->second), *sg_rule); + update_security_group_rule(*aca_port, *aca_sg, *sg_rule); break; case DELETE: - delete_security_group_rule(aca_port, *(siter->second), *sg_rule); + delete_security_group_rule(*aca_port, *aca_sg, *sg_rule); break; default: ACA_LOG_ERROR("Invalid security group rule operation type"); @@ -176,14 +220,16 @@ int Aca_Security_Group_Manager::update_security_group(Aca_Port &aca_port, return EXIT_SUCCESS; } -int Aca_Security_Group_Manager::delete_security_group(Aca_Port &aca_port, - Aca_Security_Group &aca_sg) +int Aca_Security_Group_Manager::delete_security_group(Aca_Port &input_port, + Aca_Security_Group &input_sg) { map::iterator piter; map::iterator siter; + Aca_Security_Group *aca_sg; + Aca_Port *aca_port; - string port_id = aca_port.get_id(); - string sg_id = aca_sg.get_id(); + string port_id = input_port.get_id(); + string sg_id = input_sg.get_id(); piter = this->ports.find(port_id); if (piter == this->ports.end()) { @@ -191,28 +237,33 @@ int Aca_Security_Group_Manager::delete_security_group(Aca_Port &aca_port, return EXIT_FAILURE; } + aca_port = piter->second; + siter = this->security_groups.find(sg_id); if (siter == this->security_groups.end()) { ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); return EXIT_FAILURE; } - - for (auto &it : aca_sg.get_security_group_rules()) { + aca_sg = siter->second; + + //TODO: Special processing needs when overlapping security group rules are deleted + for (auto &it : input_sg.get_security_group_rules()) { Aca_Security_Group_Rule *sg_rule = it.second; - delete_security_group_rule(aca_port, *(siter->second), *sg_rule); + delete_security_group_rule(*aca_port, *aca_sg, *sg_rule); } - aca_port.delete_security_group_id(sg_id); - - if (aca_port.get_security_group_id_num() == 0) { - Aca_Port *port = piter->second; + aca_port->delete_security_group_id(sg_id); + if (aca_port->get_security_group_num() == 0) { this->ports.erase(port_id); - delete port; + delete aca_port; } - //TODO: only delete sg when never be used by any port - //this->security_groups.erase(aca_sg.get_id()); + aca_sg->delete_port_id(port_id); + if (aca_sg->get_port_num() == 0) { + this->security_groups.erase(sg_id); + delete aca_sg; + } return EXIT_SUCCESS; } diff --git a/src/sg/aca_security_group_ovs.cpp b/src/sg/aca_security_group_ovs.cpp index 2559f515..003fd3eb 100644 --- a/src/sg/aca_security_group_ovs.cpp +++ b/src/sg/aca_security_group_ovs.cpp @@ -15,12 +15,18 @@ #include #include "aca_log.h" #include "aca_security_group_ovs.h" +#include "aca_security_group_manager.h" #include "aca_ovs_control.h" using namespace aca_ovs_control; namespace aca_security_group { +static const char *ct_state[] = { + "+est-rel-rpl", + "+new-est" +}; + Aca_Security_Group_Ovs &Aca_Security_Group_Ovs::get_instance() { // It is instantiated on first use. @@ -34,14 +40,14 @@ int Aca_Security_Group_Ovs::get_vlan_by_segment_id(const int segment_id) return segment_id; } -void Aca_Security_Group_Ovs::init_port_egress_flows(Aca_Port &aca_port) +void Aca_Security_Group_Ovs::init_port_egress_flows(Aca_Port &port) { ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); char flow[128] = {0}; - string port_id = aca_port.get_id(); - string vpc_id = aca_port.get_vpc_id(); - const char *mac_address = aca_port.get_mac_address().data(); + string port_id = port.get_id(); + string vpc_id = port.get_vpc_id(); + const char *mac_address = port.get_mac_address().data(); int ofport = 12; int patch_ofport = 13; @@ -85,7 +91,7 @@ void Aca_Security_Group_Ovs::init_port_egress_flows(Aca_Port &aca_port) controller.add_flow(BR_INT, flow); } -void Aca_Security_Group_Ovs::init_port_ingress_flows(const Aca_Port &aca_port) +void Aca_Security_Group_Ovs::init_port_ingress_flows(const Aca_Port &port) { ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); char flow[128] = {0}; @@ -111,13 +117,13 @@ void Aca_Security_Group_Ovs::init_port_ingress_flows(const Aca_Port &aca_port) controller.add_flow(BR_INT, flow); } -void Aca_Security_Group_Ovs::init_port(Aca_Port &aca_port) +void Aca_Security_Group_Ovs::init_port(Aca_Port &port) { ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); char flow[128] = {0}; - string port_id = aca_port.get_id(); - string vpc_id = aca_port.get_vpc_id(); + string port_id = port.get_id(); + string vpc_id = port.get_vpc_id(); int ofport = 12; int vni = 10; int local_vlan = get_vlan_by_segment_id(vni); @@ -128,7 +134,7 @@ void Aca_Security_Group_Ovs::init_port(Aca_Port &aca_port) controller.add_flow(BR_INT, flow); // Allow address pairs - vector> address_pairs = aca_port.get_allow_address_pairs(); + vector> address_pairs = port.get_allow_address_pairs(); for (auto iter = address_pairs.cbegin(); iter != address_pairs.cend(); iter++) { //pair address_pair = aca_port.allow_address_pairs(i); const char * ip_address = iter->first.data(); @@ -155,34 +161,39 @@ void Aca_Security_Group_Ovs::init_port(Aca_Port &aca_port) controller.add_flow(BR_INT, flow); } - init_port_egress_flows(aca_port); + init_port_egress_flows(port); - init_port_ingress_flows(aca_port); + init_port_ingress_flows(port); } -int Aca_Security_Group_Ovs::get_flow_priority(Aca_Security_Group_Rule &aca_sg_rule, - int conjunction) +int Aca_Security_Group_Ovs::flow_priority_offset(Aca_Security_Group_Rule &sg_rule, + bool conjunction) { - string remote_group_id = aca_sg_rule.get_remote_group_id(); + int conj_offset = 4; + Aca_Security_Group * remote_group = sg_rule.get_remote_group(); + Protocol protocol = sg_rule.get_protocol(); - if (remote_group_id == "" || conjunction) { + if (remote_group == NULL || conjunction) { conj_offset = 0; } - int protocol = aca_sg_rule.get_protocol(); - uint32_t port_range_min = aca_sg_rule.get_port_range_min(); - uint32_t port_range_max = aca_sg_rule.get_port_range_max(); + if (protocol == UNKNOWN_PROTO) { + return conj_offset; + } + + uint32_t port_range_min = sg_rule.get_port_range_min(); + uint32_t port_range_max = sg_rule.get_port_range_max(); if (protocol == PROTO_NUM_ICMP) { if (port_range_min == 0) { - return 70 + 1; + return conj_offset + 1; } else if (port_range_max == 0) { - return 70 + 2; + return conj_offset + 2; } } - return 70 + conj_offset; + return conj_offset + 3; } int Aca_Security_Group_Ovs::get_dl_type_by_ether_type(uint32_t ethertype) @@ -206,9 +217,9 @@ string Aca_Security_Group_Ovs::get_nw_proto_by_protocol(uint32_t protocol) return ""; } -void Aca_Security_Group_Ovs::build_flows_from_sg_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule, - bool has_actions, +int Aca_Security_Group_Ovs::build_normal_flows(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + bool need_actions, vector &flows) { stringstream match_fileds; @@ -217,17 +228,17 @@ void Aca_Security_Group_Ovs::build_flows_from_sg_rule(Aca_Port &aca_port, string nw_src_dst; string tcp_udp_dst; - uint64_t cookie = aca_sg_rule.get_cookie(); - uint32_t dl_type = aca_sg_rule.get_ethertype(); - uint32_t nw_proto = aca_sg_rule.get_protocol(); - Direction direction = aca_sg_rule.get_direction(); - uint32_t port_range_min = aca_sg_rule.get_port_range_min(); - uint32_t port_range_max = aca_sg_rule.get_port_range_max(); - string remote_ip_prefix = aca_sg_rule.get_remote_ip_prefix(); - string remote_group_id = aca_sg_rule.get_remote_group_id(); - uint32_t ofport = aca_port.get_ofport(); - - priority = get_flow_priority(aca_sg_rule, 0); + uint64_t cookie = sg_rule.get_cookie(); + uint32_t dl_type = sg_rule.get_ethertype(); + uint32_t nw_proto = sg_rule.get_protocol(); + Direction direction = sg_rule.get_direction(); + uint32_t port_range_min = sg_rule.get_port_range_min(); + uint32_t port_range_max = sg_rule.get_port_range_max(); + string remote_ip_prefix = sg_rule.get_remote_ip_prefix(); + Aca_Security_Group * remote_group = sg_rule.get_remote_group(); + uint32_t ofport = port.get_ofport(); + + priority = flow_priority_offset(sg_rule, remote_group != NULL) + FLOW_PRIORITY_BASE; //dl_type = get_dl_type_by_ether_type(ethertype); tcp_udp_dst = get_nw_proto_by_protocol(nw_proto); @@ -239,16 +250,19 @@ void Aca_Security_Group_Ovs::build_flows_from_sg_rule(Aca_Port &aca_port, match_fileds << "table=" << RULES_EGRESS_TABLE << ","; } - if (has_actions) { + if (need_actions) { match_fileds << "cookie=" << cookie << ","; } else { match_fileds << "cookie=" << cookie << "/-1,"; } match_fileds << "priority=" << priority << ","; - match_fileds << "dl_type=" << dl_type << ","; match_fileds << "reg" << REG_PORT << "=" << ofport << ","; + if (dl_type > 0) { + match_fileds << "dl_type=" << dl_type << ","; + } + if (remote_ip_prefix != "") { if (direction == INGRESS) { nw_src_dst = "nw_src=" + remote_ip_prefix ; @@ -263,28 +277,253 @@ void Aca_Security_Group_Ovs::build_flows_from_sg_rule(Aca_Port &aca_port, match_fileds << "nw_proto=" << nw_proto << ","; } - for (uint32_t i = port_range_min; i <= port_range_max; i++) { - stringstream ss; + if (nw_proto == ICMP) { + stringstream ss; string flow; + + if (port_range_min > 0) { + ss << "icmp_type=" << port_range_min; + } + + if (port_range_max > 0) { + ss << "icmp_code=" << port_range_max; + } - ss << tcp_udp_dst << "_dst=" << i; flow = match_fileds.str() + ss.str(); - if (has_actions) { + if (need_actions) { flow = flow + "," + actions; } - flows.push_back(flow); + flows.push_back(flow); + } else { + for (uint32_t i = port_range_min; i <= port_range_max; i++) { + stringstream ss; + string flow; + + ss << tcp_udp_dst << "_dst=" << i; + flow = match_fileds.str() + ss.str(); + + if (need_actions) { + flow = flow + "," + actions; + } + + flows.push_back(flow); + } } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::get_remote_group_ips(Aca_Security_Group *remote_group, + vector remote_ips) +{ + Aca_Security_Group_Manager manager = Aca_Security_Group_Manager::get_instance(); + vector &port_ids = remote_group->get_port_ids(); + + for (uint32_t i = 0; i < port_ids.size(); i++) { + string port_id = port_ids[i]; + map &ports = manager.get_ports(); + map::iterator iter; + Aca_Port *port; + + iter = ports.find(port_id); + if (iter == ports.end()) { + return EXIT_FAILURE; + } + + port = iter->second; + vector &fixed_ips = port->get_fixed_ip(); + + for (uint32_t j = 0; j < fixed_ips.size(); j++) { + remote_ips.push_back(fixed_ips[j]); + } + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::get_remote_group_conj_id(Aca_Security_Group_Rule &sg_rule) +{ + int offset; + int conj_id; + string key; + map::iterator iter; + + offset = flow_priority_offset(sg_rule, true); + + //TODU: use (sg_id, remote_sg_id, direction, ethertype) as key + key = sg_rule.get_remote_group_id(); + + iter = this->conj_ids.find(key); + if (iter == this->conj_ids.end()) { + this->conj_id_base += 8; + conj_id = this->conj_id_base + offset * 2; + this->conj_ids[key] = conj_id; + } else { + conj_id = iter->second; + } + + return conj_id; } -int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule) +int Aca_Security_Group_Ovs::build_flows_by_remote_ip(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + string remote_ip, + int conj_id, + vector &flows) +{ + stringstream match_fileds; + string actions; + int priority; + int vni = 10; + + uint64_t cookie = sg_rule.get_cookie(); + uint32_t dl_type = sg_rule.get_ethertype(); + Direction direction = sg_rule.get_direction(); + int local_vlan = get_vlan_by_segment_id(vni); + + if (direction == INGRESS) { + match_fileds << "table=" << RULES_INGRESS_TABLE << ","; + } else { + match_fileds << "table=" << RULES_EGRESS_TABLE << ","; + } + + priority = 70 + (conj_id % 8) / 2; + + match_fileds << "cookie=" << cookie << ","; + match_fileds << "priority=" << priority << ","; + match_fileds << "dl_type=" << dl_type << ","; + match_fileds << "reg" << REG_NET << "=" << local_vlan << ","; + + if (direction == INGRESS) { + match_fileds << "nw_src=" << remote_ip << ","; + } else { + match_fileds << "nw_dst=" << remote_ip << ","; + } + + return add_conjunction_actions(match_fileds.str(), conj_id, 1, flows); +} + +int Aca_Security_Group_Ovs::add_conjunction_actions(string flow, + int conj_id, + int dimension, + vector &flows) +{ + for (int i = 0; i < 2; i++) { + stringstream s_flow; + string flow; + + s_flow << "ct_state=" << ct_state[i] << ",actions=conjunction(" \ + << conj_id << "," << dimension << "/2)"; + + flows.push_back(flow + s_flow.str()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::build_accept_flows(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + int conj_id, + vector &flows) +{ + stringstream match_fileds; + int priority; + string actions; + string flow; + int vni = 10; + + uint64_t cookie = sg_rule.get_cookie(); + uint32_t dl_type = sg_rule.get_ethertype(); + Direction direction = sg_rule.get_direction(); + uint32_t ofport = port.get_ofport(); + int local_vlan = get_vlan_by_segment_id(vni); + + if (direction == INGRESS) { + match_fileds << "table=" << RULES_INGRESS_TABLE << ","; + actions = "actions=output:" + ofport; + } else { + match_fileds << "table=" << RULES_EGRESS_TABLE << ","; + actions = "actions=resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; + } + + priority = (conj_id % 8) / 2; + + match_fileds << "cookie=" << cookie << ","; + match_fileds << "priority=" << priority << ","; + match_fileds << "dl_type=" << dl_type << ","; + match_fileds << "reg" << REG_NET << "=" << local_vlan << ","; + + for (int i = 0; i < 2; i++) { + stringstream s_flow; + + match_fileds << "ct_state=" << ct_state[i] << ","; + if (i == 1 && direction == INGRESS) { + s_flow << match_fileds.str() << "conj_id=" << conj_id + 1 << ","; + s_flow << "ct(comit,zone=NXM_NX_REG" << REG_NET << "[0..15])," << actions \ + << ",resubmit(," << ACCEPTED_INGRESS_TRAFFIC_TABLE << ")"; + } else { + s_flow << match_fileds.str() << "conj_id=" << conj_id << "," << actions; + } + + flows.push_back(s_flow.str()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::build_conjunction_flows(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + bool need_actions, + vector &flows) +{ + int conj_id; + vector remote_ips; + vector normal_flows; + Aca_Security_Group *remote_group; + + remote_group = sg_rule.get_remote_group(); + if (remote_group == NULL) { + return EXIT_FAILURE; + } + + get_remote_group_ips(remote_group, remote_ips); + conj_id = get_remote_group_conj_id(sg_rule); + + for (uint32_t i = 0; i < remote_ips.size(); i++) { + build_flows_by_remote_ip(port, sg_rule, remote_ips[i], conj_id, flows); + } + + build_normal_flows(port, sg_rule, true, normal_flows); + + for (uint32_t i = 0; i < normal_flows.size(); i++) { + add_conjunction_actions(normal_flows[i], conj_id, 2, flows); + } + + return build_accept_flows(port, sg_rule, conj_id, flows); +} + + +int Aca_Security_Group_Ovs::build_flows_by_sg_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + bool need_actions, + vector &flows) +{ + if (sg_rule.get_remote_group() != NULL) { + return build_conjunction_flows(port, sg_rule, need_actions, flows); + } + + return build_normal_flows(port, sg_rule, need_actions, flows); +} + +int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule) { vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - build_flows_from_sg_rule(aca_port, aca_sg_rule, true, flows); + build_flows_by_sg_rule(port, sg_rule, true, flows); for (uint32_t i = 0; i < flows.size(); i++) { controller.add_flow(BR_INT, flows[i].data()); @@ -293,32 +532,32 @@ int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &aca_port, return EXIT_SUCCESS; } -int Aca_Security_Group_Ovs::update_port_security_group_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule) +int Aca_Security_Group_Ovs::update_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule) { vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - aca_sg_rule.set_cookie(aca_sg_rule.get_cookie() - 1); - delete_port_security_group_rule(aca_port, aca_sg_rule); - aca_sg_rule.set_cookie(aca_sg_rule.get_cookie() + 1); - - build_flows_from_sg_rule(aca_port, aca_sg_rule, true, flows); + build_flows_by_sg_rule(port, sg_rule, true, flows); for (uint32_t i = 0; i < flows.size(); i++) { controller.add_flow(BR_INT, flows[i].data()); } + + sg_rule.set_cookie(sg_rule.get_cookie() - 1); + delete_port_security_group_rule(port, sg_rule); + sg_rule.set_cookie(sg_rule.get_cookie() + 1); return EXIT_SUCCESS; } -int Aca_Security_Group_Ovs::delete_port_security_group_rule(Aca_Port &aca_port, - Aca_Security_Group_Rule &aca_sg_rule) +int Aca_Security_Group_Ovs::delete_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule) { vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - build_flows_from_sg_rule(aca_port, aca_sg_rule, false, flows); + build_flows_by_sg_rule(port, sg_rule, false, flows); for (uint32_t i = 0; i < flows.size(); i++) { controller.del_flows(BR_INT, flows[i].data()); diff --git a/src/sg/aca_sg_state_handler.cpp b/src/sg/aca_sg_state_handler.cpp index 4526caa4..090277ce 100644 --- a/src/sg/aca_sg_state_handler.cpp +++ b/src/sg/aca_sg_state_handler.cpp @@ -60,8 +60,6 @@ int Aca_Sg_State_Handler::handle_port_security_group(Aca_Port &aca_port, ACA_LOG_ERROR("=====>wrong security group operation\n"); } - delete &aca_sg; - return EXIT_FAILURE; } @@ -103,7 +101,7 @@ OperationType Aca_Sg_State_Handler::get_operation_type(alcor::schema::OperationT ACA_LOG_ERROR("Invalid operation type"); } - throw "Invalid operation type"; + return UNKNOWN_OPERATION; } Direction Aca_Sg_State_Handler::get_direction(SecurityGroupConfiguration::Direction direction) @@ -116,9 +114,8 @@ Direction Aca_Sg_State_Handler::get_direction(SecurityGroupConfiguration::Direct default: ACA_LOG_ERROR("Invalid direction"); } - - throw "Invalid direction"; + return UNKNOWN_DIRECTION; } Ethertype Aca_Sg_State_Handler::get_ethertype(alcor::schema::EtherType ethertype) @@ -132,7 +129,7 @@ Ethertype Aca_Sg_State_Handler::get_ethertype(alcor::schema::EtherType ethertype ACA_LOG_ERROR("Invalid ethertype"); } - throw "Invalid ethertype"; + return UNKNOWN_ETHERTYPE; } Protocol Aca_Sg_State_Handler::get_protocol(alcor::schema::Protocol protocol) @@ -148,12 +145,12 @@ Protocol Aca_Sg_State_Handler::get_protocol(alcor::schema::Protocol protocol) ACA_LOG_ERROR("Invalid protocol"); } - throw "Invalid protocol"; + return UNKNOWN_PROTO; } void Aca_Sg_State_Handler::parse_security_group_states(const GoalState &goal_state, - map &aca_sg_map) + map &aca_sgs) { //TODO: verify fields of port_state for (int i = 0; i < goal_state.security_group_states_size(); i++) { @@ -199,7 +196,7 @@ void Aca_Sg_State_Handler::parse_security_group_states(const GoalState &goal_sta aca_sg->add_security_group_rule(aca_sg_rule); } - aca_sg_map[sg_config.id()] = aca_sg; + aca_sgs[sg_config.id()] = aca_sg; } } @@ -209,22 +206,25 @@ int Aca_Sg_State_Handler::update_security_group_states(const GoalState &goal_sta std::vector> futures; int rc; int overall_rc = EXIT_SUCCESS; - map aca_sg_map; + map aca_sgs; + map::iterator siter; + vector aca_ports; - parse_security_group_states(goal_state, aca_sg_map); + parse_security_group_states(goal_state, aca_sgs); for (int i = 0; i < goal_state.port_states_size(); i++) { PortState port_state = goal_state.port_states(i); PortConfiguration port_config = port_state.configuration(); Aca_Port *aca_port = parse_port_state(port_state); + aca_ports.push_back(aca_port); for (int j = 0; j < port_config.security_group_ids_size(); j++) { PortConfiguration::SecurityGroupId security_group_id = port_config.security_group_ids(j); string sg_id = security_group_id.id(); - map::iterator iterator = aca_sg_map.find(sg_id); - if (iterator == aca_sg_map.end()) { + map::iterator iterator = aca_sgs.find(sg_id); + if (iterator == aca_sgs.end()) { ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); continue; } @@ -242,6 +242,30 @@ int Aca_Sg_State_Handler::update_security_group_states(const GoalState &goal_sta } } + siter = aca_sgs.begin(); + while(siter != aca_sgs.end()) { + Aca_Security_Group *aca_sg = siter->second; + map::iterator riter; + map sg_rules = aca_sg->get_security_group_rules(); + + riter = sg_rules.begin(); + while(riter != sg_rules.end()) { + Aca_Security_Group_Rule * sg_rule = riter->second; + delete sg_rule; + } + + delete aca_sg; + } + + aca_sgs.clear(); + + for (size_t i = 0; i < aca_ports.size(); i++) { + Aca_Port *aca_port = aca_ports[i]; + delete aca_port; + } + + aca_ports.clear(); + return overall_rc; } From 5f9546d1fd1eca024f05c143399177f6ab11156a Mon Sep 17 00:00:00 2001 From: chenpiaoping Date: Wed, 21 Oct 2020 15:51:42 +0800 Subject: [PATCH 3/4] Debugging of general security group rules completed --- include/aca_security_group.h | 13 ++++-- include/aca_security_group_ovs.h | 9 ++--- src/sg/aca_security_group.cpp | 57 +++++++++++++++++++-------- src/sg/aca_security_group_manager.cpp | 6 ++- src/sg/aca_security_group_ovs.cpp | 26 ++++++------ src/sg/aca_sg_state_handler.cpp | 2 + 6 files changed, 75 insertions(+), 38 deletions(-) diff --git a/include/aca_security_group.h b/include/aca_security_group.h index cd775c7b..3e549f03 100644 --- a/include/aca_security_group.h +++ b/include/aca_security_group.h @@ -21,6 +21,7 @@ #include #include #include +#include using namespace std; @@ -101,6 +102,8 @@ class Aca_Security_Group_Rule { class Aca_Security_Group { public: + Aca_Security_Group(); + Aca_Security_Group(Aca_Security_Group &sg); void set_id(string id); string get_id(void); void set_name(string name); @@ -116,7 +119,7 @@ class Aca_Security_Group { void add_port_id(string port_id); void delete_port_id(string port_id); int get_port_num(void); - vector &get_port_ids(void); + set &get_port_ids(void); void add_security_group_rule(Aca_Security_Group_Rule *sg_rule); void update_security_group_rule(Aca_Security_Group_Rule *sg_rule); void delete_security_group_rule(string sg_rule_id); @@ -130,18 +133,22 @@ class Aca_Security_Group { uint32_t revision_number; string vpc_id; OperationType operation_type; - vector port_ids; + set port_ids; map rules; }; class Aca_Port { public: + Aca_Port(); + Aca_Port(Aca_Port &port); void set_id(string id); string get_id(void); void set_name(string name); string get_name(void); void set_ofport(uint32_t ofport); uint32_t get_ofport(void); + void set_vni(uint32_t vni); + uint32_t get_vni(void); void set_format_version(uint32_t format_version); uint32_t get_format_version(void); void set_revision_number(uint32_t revision_number); @@ -171,7 +178,7 @@ class Aca_Port { string vpc_id; string mac_address; vector fixed_ips; - vector security_group_ids; + set security_group_ids; vector> allow_address_pairs; map security_groups; }; diff --git a/include/aca_security_group_ovs.h b/include/aca_security_group_ovs.h index c2bacf14..3a0069c5 100644 --- a/include/aca_security_group_ovs.h +++ b/include/aca_security_group_ovs.h @@ -53,13 +53,12 @@ namespace aca_security_group { class Aca_Security_Group_Ovs { public: static Aca_Security_Group_Ovs &get_instance(); - void init_port(Aca_Port &port); + void init_port_flows(Aca_Port &port); + void clear_port_flows(Aca_Port &port); int create_port_security_group_rule(Aca_Port &port, Aca_Security_Group_Rule &sg_rule); - int update_port_security_group_rule(Aca_Port &port, - Aca_Security_Group_Rule &sg_rule); - int delete_port_security_group_rule(Aca_Port &port, - Aca_Security_Group_Rule &sg_rule); + int update_port_security_group_rule(Aca_Port &port, Aca_Security_Group_Rule &new_sg_rule, Aca_Security_Group_Rule &old_sg_rule); + int delete_port_security_group_rule(Aca_Port &port, Aca_Security_Group_Rule &sg_rule); private: int get_vlan_by_segment_id(const int segment_id); void init_port_egress_flows(Aca_Port &port); diff --git a/src/sg/aca_security_group.cpp b/src/sg/aca_security_group.cpp index 9e6bbd8e..dd92d510 100644 --- a/src/sg/aca_security_group.cpp +++ b/src/sg/aca_security_group.cpp @@ -119,6 +119,18 @@ Aca_Security_Group * Aca_Security_Group_Rule::get_remote_group(void) { return this->remote_group; } +Aca_Security_Group::Aca_Security_Group() { +} + +Aca_Security_Group::Aca_Security_Group(Aca_Security_Group &sg) { + this->id = sg.get_id(); + this->name = sg.get_name(); + this->format_version = sg.get_format_version(); + this->revision_number = sg.get_revision_number(); + this->vpc_id = sg.get_vpc_id(); + this->operation_type = sg.get_operation_type(); +} + void Aca_Security_Group::set_id(string id) { this->id = id; } @@ -163,24 +175,18 @@ OperationType Aca_Security_Group::get_operation_type(void) { } void Aca_Security_Group::add_port_id(string port_id) { - this->port_ids.push_back(port_id); + this->port_ids.insert(port_id); } void Aca_Security_Group::delete_port_id(string port_id) { - vector::iterator it; - for (it = this->port_ids.begin(); it != this->port_ids.end(); ++it) { - if (*it == port_id) { - it = this->port_ids.erase(it); - break; - } - } + this->port_ids.erase(port_id); } int Aca_Security_Group::get_port_num(void) { return this->port_ids.size(); } -vector &Aca_Security_Group::get_port_ids(void) { +set &Aca_Security_Group::get_port_ids(void) { return this->port_ids; } @@ -219,6 +225,21 @@ map Aca_Security_Group::get_security_group_ru return this->rules; } +Aca_Port::Aca_Port() { +} + +Aca_Port::Aca_Port(Aca_Port &port) { + this->id = port.get_id(); + this->name = port.get_name(); + this->ofport = port.get_ofport(); + this->vni = port.get_vni(); + this->format_version = port.get_format_version(); + this->revision_number = port.get_revision_number(); + this->vpc_id = port.get_vpc_id(); + this->mac_address = port.get_mac_address(); + this->fixed_ips = port.get_fixed_ip(); +} + void Aca_Port::set_id(string id) { this->id = id; } @@ -243,6 +264,14 @@ uint32_t Aca_Port::get_ofport(void) { return this->ofport; } +void Aca_Port::set_vni(uint32_t vni) { + this->vni = vni; +} + +uint32_t Aca_Port::get_vni(void) { + return this->vni; +} + void Aca_Port::set_format_version(uint32_t format_version) { this->format_version = format_version; } @@ -281,17 +310,11 @@ vector &Aca_Port::get_fixed_ip(void) { } void Aca_Port::add_security_group_id(string security_group_id) { - this->security_group_ids.push_back(security_group_id); + this->security_group_ids.insert(security_group_id); } void Aca_Port::delete_security_group_id(string security_group_id) { - vector::iterator it; - for (it = this->security_group_ids.begin(); it != this->security_group_ids.end(); ++it) { - if (*it == security_group_id) { - it = this->security_group_ids.erase(it); - break; - } - } + this->security_group_ids.erase(security_group_id); } int Aca_Port::get_security_group_num(void) { diff --git a/src/sg/aca_security_group_manager.cpp b/src/sg/aca_security_group_manager.cpp index 4ec86a77..38b29981 100644 --- a/src/sg/aca_security_group_manager.cpp +++ b/src/sg/aca_security_group_manager.cpp @@ -102,7 +102,7 @@ int Aca_Security_Group_Manager::update_security_group_rule(Aca_Port &port, } sg_rule.set_cookie(aca_sg_rule->get_cookie() + 1); - sg_ovs.update_port_security_group_rule(port, sg_rule); + sg_ovs.update_port_security_group_rule(port, sg_rule, *aca_sg_rule); sg.update_security_group_rule(&sg_rule); return EXIT_SUCCESS; @@ -149,7 +149,7 @@ int Aca_Security_Group_Manager::create_security_group(Aca_Port &input_port, if (piter == this->ports.end()) { aca_port = new Aca_Port(input_port); this->ports[port_id] = aca_port; - sg_ovs.init_port(*aca_port); + sg_ovs.init_port_flows(*aca_port); } else { aca_port = piter->second; } @@ -223,6 +223,7 @@ int Aca_Security_Group_Manager::update_security_group(Aca_Port &input_port, int Aca_Security_Group_Manager::delete_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg) { + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); map::iterator piter; map::iterator siter; Aca_Security_Group *aca_sg; @@ -256,6 +257,7 @@ int Aca_Security_Group_Manager::delete_security_group(Aca_Port &input_port, aca_port->delete_security_group_id(sg_id); if (aca_port->get_security_group_num() == 0) { this->ports.erase(port_id); + sg_ovs.clear_port_flows(*aca_port); delete aca_port; } diff --git a/src/sg/aca_security_group_ovs.cpp b/src/sg/aca_security_group_ovs.cpp index 003fd3eb..3ee6eebb 100644 --- a/src/sg/aca_security_group_ovs.cpp +++ b/src/sg/aca_security_group_ovs.cpp @@ -117,7 +117,7 @@ void Aca_Security_Group_Ovs::init_port_ingress_flows(const Aca_Port &port) controller.add_flow(BR_INT, flow); } -void Aca_Security_Group_Ovs::init_port(Aca_Port &port) +void Aca_Security_Group_Ovs::init_port_flows(Aca_Port &port) { ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); char flow[128] = {0}; @@ -166,6 +166,10 @@ void Aca_Security_Group_Ovs::init_port(Aca_Port &port) init_port_ingress_flows(port); } +void Aca_Security_Group_Ovs::clear_port_flows(Aca_Port &port) +{ + //TODO: delete all flows of this port +} int Aca_Security_Group_Ovs::flow_priority_offset(Aca_Security_Group_Rule &sg_rule, bool conjunction) { @@ -319,10 +323,10 @@ int Aca_Security_Group_Ovs::get_remote_group_ips(Aca_Security_Group *remote_grou vector remote_ips) { Aca_Security_Group_Manager manager = Aca_Security_Group_Manager::get_instance(); - vector &port_ids = remote_group->get_port_ids(); - - for (uint32_t i = 0; i < port_ids.size(); i++) { - string port_id = port_ids[i]; + set &port_ids = remote_group->get_port_ids(); + + for(set::iterator it = port_ids.begin(); it != port_ids.end(); it++) { + string port_id = *it; map &ports = manager.get_ports(); map::iterator iter; Aca_Port *port; @@ -533,20 +537,20 @@ int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &port, } int Aca_Security_Group_Ovs::update_port_security_group_rule(Aca_Port &port, - Aca_Security_Group_Rule &sg_rule) + Aca_Security_Group_Rule &new_sg_rule, + Aca_Security_Group_Rule &old_sg_rule) { vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - build_flows_by_sg_rule(port, sg_rule, true, flows); + build_flows_by_sg_rule(port, new_sg_rule, true, flows); for (uint32_t i = 0; i < flows.size(); i++) { controller.add_flow(BR_INT, flows[i].data()); } - - sg_rule.set_cookie(sg_rule.get_cookie() - 1); - delete_port_security_group_rule(port, sg_rule); - sg_rule.set_cookie(sg_rule.get_cookie() + 1); + + //TODO: Consider port update + delete_port_security_group_rule(port, old_sg_rule); return EXIT_SUCCESS; } diff --git a/src/sg/aca_sg_state_handler.cpp b/src/sg/aca_sg_state_handler.cpp index 090277ce..e0217f7e 100644 --- a/src/sg/aca_sg_state_handler.cpp +++ b/src/sg/aca_sg_state_handler.cpp @@ -252,9 +252,11 @@ int Aca_Sg_State_Handler::update_security_group_states(const GoalState &goal_sta while(riter != sg_rules.end()) { Aca_Security_Group_Rule * sg_rule = riter->second; delete sg_rule; + riter++; } delete aca_sg; + siter++; } aca_sgs.clear(); From ba574b496ea2e03735332e2379a13d370cdd923f Mon Sep 17 00:00:00 2001 From: chenpiaoping Date: Wed, 21 Oct 2020 18:21:06 +0800 Subject: [PATCH 4/4] Debug conjuntion flows --- include/aca_security_group_ovs.h | 8 +- src/sg/aca_security_group_ovs.cpp | 113 ++++++++++++------ .../aca/securitygroup/SecurityGroupTest.java | 92 ++++++++++++-- .../aca/securitygroup/SecurityGroupTest.class | Bin 13662 -> 15437 bytes 4 files changed, 162 insertions(+), 51 deletions(-) diff --git a/include/aca_security_group_ovs.h b/include/aca_security_group_ovs.h index 3a0069c5..213d17c5 100644 --- a/include/aca_security_group_ovs.h +++ b/include/aca_security_group_ovs.h @@ -67,11 +67,11 @@ class Aca_Security_Group_Ovs { int get_dl_type_by_ether_type(uint32_t ether_type); string get_nw_proto_by_protocol(uint32_t protocol); int get_remote_group_conj_id(Aca_Security_Group_Rule &sg_rule); - int build_flows_by_sg_rule(Aca_Port &port,Aca_Security_Group_Rule &sg_rule,bool has_actions, vector &flows); - int build_conjunction_flows(Aca_Port &port, Aca_Security_Group_Rule &sg_rule,bool need_actions, vector &flows); - int get_remote_group_ips(Aca_Security_Group *remote_group, vector remote_ips); + int build_flows_by_sg_rule(Aca_Port &port,Aca_Security_Group_Rule &sg_rule, bool del_flow, vector &flows); + int build_conjunction_flows(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, vector &flows); + int get_remote_group_ips(Aca_Security_Group *remote_group, vector &remote_ips); int build_flows_by_remote_ip(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, string remote_ip, int conj_id, vector &flows); - int build_normal_flows(Aca_Port &port,Aca_Security_Group_Rule &sg_rule,bool need_actions, vector &flows); + int build_flow_match_fileds(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, bool del_flow, vector &flows); int add_conjunction_actions(string _flow, int conj_id, int dimension, vector &flows); int build_accept_flows(Aca_Port &port,Aca_Security_Group_Rule &sg_rule, int conj_id, vector &flows); diff --git a/src/sg/aca_security_group_ovs.cpp b/src/sg/aca_security_group_ovs.cpp index 3ee6eebb..c0ba327c 100644 --- a/src/sg/aca_security_group_ovs.cpp +++ b/src/sg/aca_security_group_ovs.cpp @@ -221,14 +221,13 @@ string Aca_Security_Group_Ovs::get_nw_proto_by_protocol(uint32_t protocol) return ""; } -int Aca_Security_Group_Ovs::build_normal_flows(Aca_Port &port, +int Aca_Security_Group_Ovs::build_flow_match_fileds(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, - bool need_actions, + bool del_flow, vector &flows) { stringstream match_fileds; int priority; - string actions; string nw_src_dst; string tcp_udp_dst; @@ -247,17 +246,15 @@ int Aca_Security_Group_Ovs::build_normal_flows(Aca_Port &port, tcp_udp_dst = get_nw_proto_by_protocol(nw_proto); if (direction == INGRESS) { - actions = "actions=output:" + ofport; match_fileds << "table=" << RULES_INGRESS_TABLE << ","; } else { - actions = "actions=resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; match_fileds << "table=" << RULES_EGRESS_TABLE << ","; } - if (need_actions) { - match_fileds << "cookie=" << cookie << ","; - } else { + if (del_flow) { match_fileds << "cookie=" << cookie << "/-1,"; + } else { + match_fileds << "cookie=" << cookie << ","; } match_fileds << "priority=" << priority << ","; @@ -295,10 +292,6 @@ int Aca_Security_Group_Ovs::build_normal_flows(Aca_Port &port, flow = match_fileds.str() + ss.str(); - if (need_actions) { - flow = flow + "," + actions; - } - flows.push_back(flow); } else { for (uint32_t i = port_range_min; i <= port_range_max; i++) { @@ -308,10 +301,6 @@ int Aca_Security_Group_Ovs::build_normal_flows(Aca_Port &port, ss << tcp_udp_dst << "_dst=" << i; flow = match_fileds.str() + ss.str(); - if (need_actions) { - flow = flow + "," + actions; - } - flows.push_back(flow); } } @@ -320,7 +309,7 @@ int Aca_Security_Group_Ovs::build_normal_flows(Aca_Port &port, } int Aca_Security_Group_Ovs::get_remote_group_ips(Aca_Security_Group *remote_group, - vector remote_ips) + vector &remote_ips) { Aca_Security_Group_Manager manager = Aca_Security_Group_Manager::get_instance(); set &port_ids = remote_group->get_port_ids(); @@ -401,9 +390,9 @@ int Aca_Security_Group_Ovs::build_flows_by_remote_ip(Aca_Port &port, match_fileds << "reg" << REG_NET << "=" << local_vlan << ","; if (direction == INGRESS) { - match_fileds << "nw_src=" << remote_ip << ","; + match_fileds << "nw_src=" << remote_ip; } else { - match_fileds << "nw_dst=" << remote_ip << ","; + match_fileds << "nw_dst=" << remote_ip; } return add_conjunction_actions(match_fileds.str(), conj_id, 1, flows); @@ -416,10 +405,9 @@ int Aca_Security_Group_Ovs::add_conjunction_actions(string flow, { for (int i = 0; i < 2; i++) { stringstream s_flow; - string flow; - s_flow << "ct_state=" << ct_state[i] << ",actions=conjunction(" \ - << conj_id << "," << dimension << "/2)"; + s_flow << ",ct_state=" << ct_state[i] << ",actions=conjunction(" \ + << conj_id + i << "," << dimension << "/2)"; flows.push_back(flow + s_flow.str()); } @@ -446,10 +434,10 @@ int Aca_Security_Group_Ovs::build_accept_flows(Aca_Port &port, if (direction == INGRESS) { match_fileds << "table=" << RULES_INGRESS_TABLE << ","; - actions = "actions=output:" + ofport; + actions = "output:" + to_string(ofport); } else { match_fileds << "table=" << RULES_EGRESS_TABLE << ","; - actions = "actions=resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; + actions = "resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; } priority = (conj_id % 8) / 2; @@ -465,10 +453,10 @@ int Aca_Security_Group_Ovs::build_accept_flows(Aca_Port &port, match_fileds << "ct_state=" << ct_state[i] << ","; if (i == 1 && direction == INGRESS) { s_flow << match_fileds.str() << "conj_id=" << conj_id + 1 << ","; - s_flow << "ct(comit,zone=NXM_NX_REG" << REG_NET << "[0..15])," << actions \ + s_flow << "actions=ct(commit,zone=NXM_NX_REG" << REG_NET << "[0..15])," << actions \ << ",resubmit(," << ACCEPTED_INGRESS_TRAFFIC_TABLE << ")"; } else { - s_flow << match_fileds.str() << "conj_id=" << conj_id << "," << actions; + s_flow << match_fileds.str() << "conj_id=" << conj_id << ",actions=" << actions; } flows.push_back(s_flow.str()); @@ -479,12 +467,11 @@ int Aca_Security_Group_Ovs::build_accept_flows(Aca_Port &port, int Aca_Security_Group_Ovs::build_conjunction_flows(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, - bool need_actions, vector &flows) { int conj_id; vector remote_ips; - vector normal_flows; + vector match_fileds; Aca_Security_Group *remote_group; remote_group = sg_rule.get_remote_group(); @@ -492,17 +479,21 @@ int Aca_Security_Group_Ovs::build_conjunction_flows(Aca_Port &port, return EXIT_FAILURE; } - get_remote_group_ips(remote_group, remote_ips); + if (get_remote_group_ips(remote_group, remote_ips) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Get ips of remote group failed\n"); + return EXIT_FAILURE; + } + conj_id = get_remote_group_conj_id(sg_rule); for (uint32_t i = 0; i < remote_ips.size(); i++) { build_flows_by_remote_ip(port, sg_rule, remote_ips[i], conj_id, flows); } - build_normal_flows(port, sg_rule, true, normal_flows); + build_flow_match_fileds(port, sg_rule, false, match_fileds); - for (uint32_t i = 0; i < normal_flows.size(); i++) { - add_conjunction_actions(normal_flows[i], conj_id, 2, flows); + for (uint32_t i = 0; i < match_fileds.size(); i++) { + add_conjunction_actions(match_fileds[i], conj_id, 2, flows); } return build_accept_flows(port, sg_rule, conj_id, flows); @@ -511,14 +502,51 @@ int Aca_Security_Group_Ovs::build_conjunction_flows(Aca_Port &port, int Aca_Security_Group_Ovs::build_flows_by_sg_rule(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, - bool need_actions, + bool del_flow, vector &flows) { + Direction direction; + uint32_t ofport; + string actions; + vector tmp_flows; + if (sg_rule.get_remote_group() != NULL) { - return build_conjunction_flows(port, sg_rule, need_actions, flows); + return build_conjunction_flows(port, sg_rule, flows); } - return build_normal_flows(port, sg_rule, need_actions, flows); + build_flow_match_fileds(port, sg_rule, del_flow, tmp_flows); + + direction = sg_rule.get_direction(); + ofport = port.get_ofport(); + + if (direction == INGRESS) { + actions = "actions=output:" + ofport; + } else { + actions = "actions=resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; + } + + for (uint32_t i = 0; i < tmp_flows.size(); i++) { + string flow = tmp_flows[i]; + + for (int j = 0; j < 2; j++) { + stringstream s_flow; + + s_flow << flow << ",ct_state=" << ct_state[j]; + + if (!del_flow) { + if (j == 1 && direction == INGRESS) { + s_flow << "ct(comit,zone=NXM_NX_REG" << REG_NET << "[0..15])," << actions \ + << ",resubmit(," << ACCEPTED_INGRESS_TRAFFIC_TABLE << ")"; + } else { + s_flow << "," << actions; + } + } + + flows.push_back(s_flow.str()); + } + } + + return EXIT_SUCCESS; } int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &port, @@ -527,7 +555,10 @@ int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &port, vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - build_flows_by_sg_rule(port, sg_rule, true, flows); + if (build_flows_by_sg_rule(port, sg_rule, false, flows) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Build flows by sg rule failed\n"); + return EXIT_FAILURE; + } for (uint32_t i = 0; i < flows.size(); i++) { controller.add_flow(BR_INT, flows[i].data()); @@ -543,7 +574,10 @@ int Aca_Security_Group_Ovs::update_port_security_group_rule(Aca_Port &port, vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - build_flows_by_sg_rule(port, new_sg_rule, true, flows); + if (build_flows_by_sg_rule(port, new_sg_rule, false, flows) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Build flows by sg rule failed\n"); + return EXIT_FAILURE; + } for (uint32_t i = 0; i < flows.size(); i++) { controller.add_flow(BR_INT, flows[i].data()); @@ -561,7 +595,10 @@ int Aca_Security_Group_Ovs::delete_port_security_group_rule(Aca_Port &port, vector flows; ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); - build_flows_by_sg_rule(port, sg_rule, false, flows); + if (build_flows_by_sg_rule(port, sg_rule, true, flows) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Build flows by sg rule failed\n"); + return EXIT_FAILURE; + } for (uint32_t i = 0; i < flows.size(); i++) { controller.del_flows(BR_INT, flows[i].data()); diff --git a/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java b/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java index fb57f689..52724386 100644 --- a/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java +++ b/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java @@ -44,6 +44,11 @@ public SecurityGroupTest() { .usePlaintext().build(); } + @Override + protected void finalize() { + managedChannel.shutdown(); + } + private VpcState buildVpcState() { VpcConfiguration.Builder vpcConfigBuilder = VpcConfiguration.newBuilder(); vpcConfigBuilder.setName("vpc1"); @@ -93,6 +98,29 @@ private PortState buildPortState() { return portStateBuilder.build(); } + private PortState buildPortState2() { + PortConfiguration.Builder portConfigBuilder = PortConfiguration.newBuilder(); + portConfigBuilder.setName("port2"); + portConfigBuilder.setVpcId("vpc_id1"); + portConfigBuilder.setId("port_id2"); + portConfigBuilder.setFormatVersion(2); + portConfigBuilder.setRevisionNumber(2); + portConfigBuilder.setAdminStateUp(true); + portConfigBuilder.setMessageType(Common.MessageType.FULL); + portConfigBuilder.setMacAddress("7E:04:D0:A9:42:53"); + portConfigBuilder.addFixedIps(PortConfiguration.FixedIp.newBuilder() + .setIpAddress("10.10.10.3").setSubnetId("subnet_id1").build()); + PortConfiguration.SecurityGroupId.Builder securityGroupIdBuilder = PortConfiguration.SecurityGroupId.newBuilder(); + securityGroupIdBuilder.setId("security_group_id2"); + portConfigBuilder.addSecurityGroupIds(securityGroupIdBuilder.build()); + + PortState.Builder portStateBuilder = PortState.newBuilder(); + portStateBuilder.setOperationType(OperationType.CREATE); + portStateBuilder.setConfiguration(portConfigBuilder.build()); + + return portStateBuilder.build(); + } + private SecurityGroupState buildSecurityGroupState() { SecurityGroupConfiguration.Builder securityGroupConfigBuilder = SecurityGroupConfiguration.newBuilder(); securityGroupConfigBuilder.setName("security_group1"); @@ -109,7 +137,7 @@ private SecurityGroupState buildSecurityGroupState() { securityGroupRuleBuilder.setProtocol(Protocol.TCP); securityGroupRuleBuilder.setPortRangeMin(100); securityGroupRuleBuilder.setPortRangeMax(101); - securityGroupRuleBuilder.setRemoteIpPrefix("12.12.12.0/24"); + securityGroupRuleBuilder.setRemoteIpPrefix("11.11.11.0/24"); securityGroupConfigBuilder.addSecurityGroupRules(securityGroupRuleBuilder.build()); SecurityGroupState.Builder securityGroupStateBuilder = SecurityGroupState.newBuilder(); @@ -119,27 +147,73 @@ private SecurityGroupState buildSecurityGroupState() { return securityGroupStateBuilder.build(); } - public void pushNetworkResourceStatesTest() { - GoalStateProvisionerBlockingStub blockingStub = - GoalStateProvisionerGrpc.newBlockingStub(managedChannel); + private SecurityGroupState buildSecurityGroupState2() { + SecurityGroupConfiguration.Builder securityGroupConfigBuilder = SecurityGroupConfiguration.newBuilder(); + securityGroupConfigBuilder.setName("security_group2"); + securityGroupConfigBuilder.setVpcId("vpc_id1"); + securityGroupConfigBuilder.setId("security_group_id2"); + securityGroupConfigBuilder.setFormatVersion(2); + securityGroupConfigBuilder.setRevisionNumber(2); + SecurityGroupRule.Builder securityGroupRuleBuilder = SecurityGroupRule.newBuilder(); + securityGroupRuleBuilder.setOperationType(OperationType.CREATE); + securityGroupRuleBuilder.setId("security_group_rule_id2"); + securityGroupRuleBuilder.setSecurityGroupId("security_group_id2"); + securityGroupRuleBuilder.setDirection(Direction.INGRESS); + securityGroupRuleBuilder.setEthertype(EtherType.IPV4); + securityGroupRuleBuilder.setProtocol(Protocol.UDP); + securityGroupRuleBuilder.setPortRangeMin(200); + securityGroupRuleBuilder.setPortRangeMax(201); + securityGroupRuleBuilder.setRemoteGroupId("security_group_id1"); + securityGroupConfigBuilder.addSecurityGroupRules(securityGroupRuleBuilder.build()); + + SecurityGroupState.Builder securityGroupStateBuilder = SecurityGroupState.newBuilder(); + securityGroupStateBuilder.setOperationType(OperationType.CREATE); + securityGroupStateBuilder.setConfiguration(securityGroupConfigBuilder.build()); + + return securityGroupStateBuilder.build(); + } + private GoalState buildGoalState(PortState portState, SecurityGroupState securityGroupState) { GoalState.Builder builder = GoalState.newBuilder(); builder.setFormatVersion(1); builder.addVpcStates(buildVpcState()); builder.addSubnetStates(buildSubnetState()); - builder.addPortStates(buildPortState()); - builder.addSecurityGroupStates(buildSecurityGroupState()); + builder.addPortStates(portState); + builder.addSecurityGroupStates(securityGroupState); + + return builder.build(); + } + + private void pushNetworkResourceStates(GoalState goalState) { + GoalStateProvisionerBlockingStub blockingStub = + GoalStateProvisionerGrpc.newBlockingStub(managedChannel); GoalStateOperationReply goalStateOperationReply - = blockingStub.pushNetworkResourceStates(builder.build()); + = blockingStub.pushNetworkResourceStates(goalState); System.out.println(goalStateOperationReply.toString()); + } - managedChannel.shutdown(); + private void createGeneralSecurityGroupTest() { + PortState portState = buildPortState(); + SecurityGroupState securityGroupState = buildSecurityGroupState(); + GoalState goalState = buildGoalState(portState, securityGroupState); + pushNetworkResourceStates(goalState); + } + + private void createRemoteGroupSecurityGroupTest() { + createGeneralSecurityGroupTest(); + + PortState portState = buildPortState2(); + SecurityGroupState securityGroupState = buildSecurityGroupState2(); + GoalState goalState = buildGoalState(portState, securityGroupState); + pushNetworkResourceStates(goalState); } public static void main(String[] args) { SecurityGroupTest securityGroupTest = new SecurityGroupTest(); - securityGroupTest.pushNetworkResourceStatesTest(); + //securityGroupTest.createGeneralSecurityGroupTest(); + + securityGroupTest.createRemoteGroupSecurityGroupTest(); } } diff --git a/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class b/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class index 4ac5c4674ba660ef8c3e9575cd41f02d7969a5e3..36ee8232604932fd479a483f8235244e69756284 100644 GIT binary patch literal 15437 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 M-r}0%nnHR12imD?$p8QV delta 3651 zcmZ`*33OCN7QHtK`AzrlCWMgChAfbfJs}AahzJS00TLkr+Q=G`CWIvkS=dbn+ywzs z;;y)FxPkbMqJZFviYV?o>dY|W;OM9`BQwst`rV+OIde{*|LWC$_3GYRuio$1SADwJ zdFYp?_W~HkuXZ}OlPT)Eg2b+@808Kt?>mTySkYWt;6yqy3}l+fLbhrOyKZ_e;V#I} z3;yy47oM#{2Ajx7Hes~-+r~E3wKz~HjwG1ZP-o{j+r&^E&_e>s>YNyc;RcFL48%D^ zx|-&R@5(aN+VGLCb1~AuC=(?pwE>xinjh^}KZcjM#$c?0aVExNLJ+H=K8bLv&(3d+^c9_wW3`TG4-3X9P(Leq$?YO87UOI#(Y3{2Nh zW)MRaQ!-RiWL3ORvuR(@=x-AO)ws~WEG@!pVq_@Btu{Ly>QLkbgR3!D3ozS(`GhmL zD#*MV3pDfDPSn9~V4>coUQII^Jq=iFV2LKPG`MZ9`q^0Ns79j(+N9PSd4j`c(tzcf zNsHR&Xm>TBO$W3S1;QjrH50i;%+R)Tk(Y|bfzeR^$W1)g}ZNqg2t~YT5ZWI9$yUb|y zp=*Sr12>zv1-GgMa|5@l+s)XF4%}hlP7TK`Ny}?$N7vQ0_*+|@xEuEvxL32hFUX-- z#knUXJ|L=}smVeocHkic51V)dj}oJWYOzZ8IMjaklH?uOX=0b2cS-Il`+#*p?!ay> z>l32da24e?bOm+bNfX_8N^SFO^z6Yi2AQNAE^DkvsAv*E}WzI zNEgn>>SXjX*HL_`13n{iL)-RLn{y-GP8`D*2ENpreWms$7OT!!w;B~QJ>`!?uitZ% zGCGbw8~9q6(FtO*dM>d@;yt>Qy8130a2$Wpm2^VKeXH5qqwjRVd{0cxC{s1A1a%}P zKVI}bjvsXKeDB0h_`89BXaxTxW`vR^sd2IXUO0t+8Thy6{0lKB^e$cXjk}&uN0PlR z0dqWu*89tARyk<**2263`xor3r#RST zKEqF6uw_kc{<7w&E&hcKt2FOIIa3ZHs^v^4s;zOobtxU^P?JR*re-A^^c3?PgCj&+ zo=c1n0Y<3$#3`;(EHPLrvU0Q>`a#!mj@7Bg5fdfV1kVU3M{$Cb4<}MCdx5EsEkmvA zktjA^%}tJy6lHqJB%(x?6rb*>oWgR06(-N8^xGk-ASFp{&x=t#2X%TXS!GZ+TS~Ld zlUI4FVL*w;#|sQrOO^0KqDZET)HeghB+oWENB3;^g7$``b<&sYp6#TM^GwcXjj9;9 zI;GZRooBo@N%)qCHew*>`<-!nZRWx8`-2vCRU@Jf?caicnt*66yLn+T^<8R=`fQLHX;9Qk6%MIt zUx68J@C*6y&T|=%&k7b z+c?2C;s0Q}oA-pU-OKxIY*M&EY;+3~t@TCSSRvTfS^-=XRBVHoOD$aP%Z{*crTx6x zes1+;@4~efZjyl8EZpwP?#5lw_gi>SlX=X-;}$HT^mKVn^gavE`Lcz`ixysyxz{Ul z?IU>0mn%o`o`ny6xfVY8m1RW$eFV-V0X11@P7#{rLbC!%IA3T^m4cWihf;}iP$dFP zm#8XvGee#;aUp!DmH$`uGHSvstil{y5?x3_@yv0p=KXv?B&k9cALI^^q+Sm0AwDc( z1j6)f4XKkMuk_Nb-S}M8`GbW&1;zPBjBqH z@s?u+TCoOg2yBqL-H4UH5pL@l;WqIRJ}SaxqMna&r>L_=gxkf(ML6n45~}z^A>Aso zcB5Z6Cr|0-wDOz?i!*&WSr%tmoNEsjSoGV228&DWL36-jt1ZAvi)$)&u~X^l*U^+?4A&d6NC&a8w-h|1v?mh5UKgsK-$f?}$D<+SG z1DgfU7Rj~M-YYh^fY0z*dFMb6?v?gMVX;sAFz)AbVtf7jI_T^*1cKkmA||z`Ih)Q zaJN0bNBpDWAHW{lKg`2zd|M`t;;=n&jPLM0@sHz}?f)e9eeqA>C+*WA{s*OAM#}~t qitR7